Does std::make_shared value initialize class members whose default ctor does not initialize?

500 Views Asked by At

Does std::make_shared value initalize members when there is a default ctor that fails to initailize its members?

I stumbled upon this when using a class where the default ctor did not initialize members using RAII style gave a warning and wondered why no warning was issued when it was used before elsewhere. Elsewhere it was using std::make_shared and I was thinking why it had been working before and no warning was issued.

#include <iostream>
#include <memory>

class Foo
{
public:
    Foo() {} // should initalize mode but does not

    int mode;

    bool isZero() const
    {
        if (mode == 0) {
            return true;
        }
        return false;
    }
};

int main(int argc, const char* argv[])
{
    auto blaa = std::make_shared<Foo>();
    if (blaa->isZero()) { // No warning. Always zero initialized because using make_shared?
        std::cout << "blaa.mode is zero\n";
    }
    Foo foo;
    if (foo.isZero()) { // warning: 'foo' is used uninitialized in this function - as expected
        std::cout << "foo.mode is zero\n";
    }
    return 0;
}
2

There are 2 best solutions below

4
Sam Varshavchik On BEST ANSWER

No, make_shared does not do anything different, with respect to constructing an object, than otherwise happens when an object gets constructed in any other way. All objects follow the same rules when they get constructed in C++.

Your constructor fails to initialize mode. Just because it happens to be zero, when it's constructed in dynamic scope, with your compiler, and your operating system: that doesn't mean anything, and this does not give you any guarantees as to what happens when the object gets constructed in automatic scope (or vice versa).

This is undefined behavior. As far as compiler warnings go: the compiler is not obligated to issue a warning message for undefined behavior. Any such warning message should simply be considered to be an unexpected bonus and a surprise. Your compiler does not detect undefined behavior in one of your two test cases, and that's simply how it is.

0
Bogdan Ariton On

With make_shared you are creating a shared pointer that retains the ownership of an object through a pointer. Which means that there is an internal counter which tracks this ownership. Here is a more detailed explanation: https://en.cppreference.com/w/cpp/memory/shared_ptr. Just as Sam Varshavchik mentioned in his answer make_shared will not do anything different in terms of initialization.

What you might be wondering is why there are different values for mode when you use make shared vs just a simple Foo declaration, like you see here in this picture: Locals view in Visual Studio

The 0xcdcdcdcd bit pattern indicates that this memory has been initialized by the memory allocator (malloc() or new) but has not been initialized by your software (object constructor or local code).

The 0xcccccccc bit pattern is used to initialize memory in data that is on the stack.