Class inside a Struct?

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Fri Jan 30 12:28:28 PST 2015


On 01/30/2015 11:59 AM, chardetm wrote:

 > struct Container {
 >
 >      private RedBlackTree!int _rbtree = new RedBlackTree!int;

I think you are expecting the new expression to be be executed for every 
object individually. It is not the case: That new expression determines 
the initial value of the _rbtree for every single object of type 
Container. As a result, they will all be sharing the same tree.

The best solution is

1) Remove the new expression:

     private RedBlackTree!int _rbtree;

2) Use a static opCall:

     private RedBlackTree!int _rbtree;

     static Container opCall()
     {
         Container container;
         container._rbtree = new RedBlackTree!int;
         return container;
     }

3) And then initialize the variables with the following syntax:

     auto c1 = Container();
     auto c2 = Container();

Importantly, do not use the following syntax:

     Container c1;    // Warning: c1._rbttree is null

So the safe solution is (used to be?) to disable the default constructor:

     @disable this();

However, the compilation fails with the following error message:

Error: struct deneme.Container static opCall is hidden by constructors 
and can never be called

That looks like a bug to me because I am explicitly disabling the 
default constructor. Right?

In any case, an alternative solution is not to use opCall() but do what 
the first part of the second part of the same error message recommends:

Please use a factory method instead, or replace all constructors with 
static opCall.

Yes, you can have factory method that returns a Container object. The 
whole program with that second method:

import std.stdio;
import std.container.rbtree;

struct Container {
     private RedBlackTree!int _rbtree;

     @disable this();               // <-- disabled

     this(RedBlackTree!int rbtree)  // <-- good practice
                                    // ("parameterize from above")
     {
         _rbtree = rbtree;
     }

     void add (int elt) {
         _rbtree.insert(elt);
     }

     void print () {
         if (_rbtree.empty) {
             writeln("empty");
         } else {
             foreach (l; _rbtree) {
                 write(l, " ");
             }
             writeln();
         }
     }

}

Container makeContainer()          // <-- factory method
{
     return Container(new RedBlackTree!int);
}

int main () {
     auto c1 = makeContainer();
     auto c2 = makeContainer();

     c1.add(1);
     c1.print();
     c2.print();
     return 0;
}

Ali



More information about the Digitalmars-d-learn mailing list