0

Consider this snippet:

struct A
{
    A(std::unique_ptr<int> somePtr_)
    : somePtr{std::move(somePtr_)},
      someInt{*somePtr}
    {};
    
    std::unique_ptr<int> somePtr;
    const int& someInt;
};

Here, a unique_ptr is passed and stored.

Then a reference to the underlying data is also stored.

When an object of A is destroyed, first someInt gets out of scope and then somePtr.

IMHO the order of the members matters when smart pointers are involved, isn't it?

But is this design not somewhat brittle?

What if someone changes the member order?

Is there a better/canonical design where there is no need of relying on the member order, or is it just like it is with RAII?

Juergen
  • 3,489
  • 6
  • 35
  • 59
  • If someone changes member order then let them initialize the int reference on their own. To talk about a better canonical design, first decide why do you need those two, a pointer and a ref. – bipll Nov 16 '20 at 10:34
  • A better solution might be moving `unique_ptr` into a (private) base class or making `someInt` a member function instead of a data member. – Evg Nov 16 '20 at 10:39

1 Answers1

4

Order of members matters always.

The presence of the smart pointer is a red hering. The crux in your example is just that initialization of one member depends on some other member already being initialized.

Members are initialized in the order they appear in the class definition. Always.

Even if you list them in different order in the member initializer list, they are still initialized in the order they appear in the class definition. And usually compilers warn when the order is different.

You get similar issue with:

struct foo {
    int x;
    int y;
    foo() : x(1),y(this->x * 2) {}
};

Changing the order of x and y would render the initialization undefined (y would use uninitialzed x).

But is this design not somewhat brittle?

Yes it is. You need to be extra careful when initialization of members depends on each other.

What if someone changes the member order?

You will get a compiler warning, that you better not ignore.

Is there a better/canonical design where there is no need of relying on the member order, or is it just like it is with RAII?

You probably do not need a reference and a smart pointer. Get rid of one of them. As they are both public there is really no point in having them both.

In general, what was suggested in a comment may be a solution. If you refactor one member to be member of a base class then there is no doubt about order of initialization, because base classes are initialized first.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185