Passing parameter when creating object array
Chris Nicholson-Sauls
ibisbasenji at gmail.com
Tue Aug 7 14:24:06 PDT 2007
Chris Nicholson-Sauls wrote:
> 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
Oh yes, I should probably also mention that my test program was creating
arrays of 1000 objects -- not just 50. :) So for use cases such as in
the OP, the difference is utterly insignificant.
-- Chris Nicholson-Sauls
More information about the Digitalmars-d-learn
mailing list