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