RedBlackTree thin wrapper initialization
Edwin van Leeuwen via Digitalmars-d
digitalmars-d at puremagic.com
Thu May 29 04:45:59 PDT 2014
On Wednesday, 28 May 2014 at 16:25:40 UTC, Rene Zwanenburg wrote:
> On Wednesday, 28 May 2014 at 09:37:55 UTC, Edwin van Leeuwen
> wrote:
>> Thank you for the reply. Does this mean I should never
>> initialize classes/objects like that or is it more specific to
>> RBT?
>
> It's the same for any class.
>
>> I guess structs have the same problem with classes/objects?
>
> That's right.
>
>> That makes struct that hold objects quite awkward to use,
>> since you can't define a default constructor for structs.
>>
>> struct S
>> {
>> auto tree = new RedBlackTree!string();
>> }
>
> There is a workaround for struct default construction. First
> let me describe the way D initialization works:
>
> Every type, built in or user defined, has an init value. For
> ints this is 0, floats NaN, and so on. User defined types have
> their init value stored in the corresponding TypeInfo, for
> example [0], [1].
>
> When initializing a value type the space is already reserved,
> either on the stack or on the heap inside a dynamic array. All
> the runtime does is memcpy the init value of that type to the
> right location.
>
> When new-ing a class the GC first allocates some space on the
> heap. Then it copies the init value to that location, just like
> with a value type. Finally it calls a constructor on the newly
> allocated object.
>
> When declaring a field in your struct or class and assign a
> default value to it, it ends up in the init value for your
> type. For example:
>
> class C
> {
> int i = uniform(0, 10); // Uniform random number
> }
>
> The generated random value will end up in C's init value and
> thus be the same for every instance. Generating the number in a
> constructor will of course result in a fresh random number for
> every instance.
>
> The reason initialization works this way is, as I understand
> it, both safety and speed. The memcpy will never fail, so if
> you successfully allocated the space for something it will
> _always_ be properly initialized. And since the init value of
> everything is known at compile time the init values of
> composite types contain the init values of all contained
> fields. In other words, no matter how complex your type, it
> will always be initialized with a single memcpy.
>
> Now, a workaround for struct default constructors is to use
> static opCall:
>
> struct S
> {
> int i;
>
> @disable this(); // Disable default initialization. See the
> comment in [1]
>
> private this(int i)
> {
> this.i = i;
> }
>
> static auto opCall()
> {
> return S(uniform(0, 10));
> }
> }
>
> void main()
> {
> S s; // Should not compile. No init value for S
> auto s = S(); // Calls S.opCall
> }
>
> I hope my ramblings make it a bit more clear what is happening
> instead of confusing the hell out of you ;). I didn't try any
> of this code so there may be some typos.
>
>
> [0]https://github.com/D-Programming-Language/druntime/blob/master/src/object_.d#L844
> [1]
> https://github.com/D-Programming-Language/druntime/blob/master/src/object_.d#L1060
Thank you very much for the clear description! That cleared
things up a lot.
More information about the Digitalmars-d
mailing list