Passing parameter when creating object array

Chris Nicholson-Sauls ibisbasenji at gmail.com
Tue Aug 7 14:22:50 PDT 2007


Kirk McDonald wrote:
> Chris Nicholson-Sauls wrote:
>> James Dennett wrote:
>>> Daniel White wrote:
>>>> I've just found out from elsewhere that it's not possible in C++ to 
>>>> create an array of objects whilst simultaneously passing a parameter 
>>>> to the constructor of each of those objects. Something like this 
>>>> returns an error:
>>>>
>>>> Myclass x (10)[50]
>>>>
>>>> I don't want to have to do:
>>>>
>>>> Myclass x[5] = {10,10,10,10,10,10.................}  // ...and so on
>>>>
>>>> Does D support the more intuitive Myclass x (10)[50] mechanism?
>>>
>>> C++ has a library type for arrays, where you can write
>>>
>>> std::vector<MyClass> x(50, MyClass(10));
>>>
>>> D tends to prefer pushing this kind of thing out of the library
>>> and into the language, but maybe somebody can point out the D
>>> library solution for this.
>>>
>>> -- James
>>
>> Its straightforward:
>>
>> T[] populateArray (T) (int len, lazy T ctor) {
>>     T[] result = new T[len];
>>
>>     foreach (inout elem; result) {
>>         elem = ctor();
>>     }
>>     return result;
>> }
>>
>>
>> Usage is like so:
>>
>> auto array = populateArray(50, new MyClass(10));
>>
>>
>>
>> This also works fine with structures, and technically any other type. 
>> Although its inefficient for basic scalars, for that use a 
>> slice-assignment:
>>
>> int[]   arr1 = new int[50]; arr1[] = 10;
>> int[50] arr2;               arr2[] = 10;
>>
>>
>> -- Chris Nicholson-Sauls
> 
> Using new on a dynamic array type already allows you to pass something 
> looking like a constructor call:
> 
> auto a = new int[](50); // An array of 50 elements
> 
> It might be appropriate to add a second, optional parameter to this 
> constructor, with the array's default initializer:
> 
> auto b = new int[](50, 5); // An array of 50 5s
> 
> This implies that, for arrays of class references, saying this
> 
> auto c = new Foo[](10, new Foo);
> 
> would result in an array of 10 references to the same instance of Foo. I 
> believe that any other behavior would be surprising.
> 
> Therefore, some notation must be provided for allocating an array and 
> not initializing its contents, which would allow something like your 
> lazy initializer above to operate without initializing the array's 
> contents first. A number of ideas occur to me; the simplest is perhaps 
> an optional argument to 'new' itself:
> 
> auto d = new(false) Foo[](10); // Allocate array, don't initialize it.
> 
> All of this being said, I am not sure how serious of an issue this 
> really is.
> 

Hmm.  That could be rather dangerous, actually.  So here's another 
thought.  Let's get 'new int[5][10][15]' working, then redefine the 
trailing parentheses to specify an initializor, and then furthermore 
make that initializor lazy anytime it is more complex than a literal or 
symbol, possibly including 'symbol.symbol' as field reads.

auto array = new MyClass[50](new MyClass(10));

You know, now that I actually see it... I'm not so fond of it.

But honestly, I don't think the cost is worth worrying too much about. 
I ran a quick test timing my function above against a simple foreach 
over an pre-allocated array.  The 'populate' function averaged only 10 
microseconds slower.  I, for one, can handle 10 millionths of almost 
anything.  :)

-- Chris Nicholson-Sauls


More information about the Digitalmars-d-learn mailing list