简体   繁体   中英

C++ Order of class members when smart pointers are involved matters

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM