Hrachya_h
Hrachya_h

Reputation: 11

C++ User defined empty default constructor vs implicit or default-ed default constructor

I am using Visual Studio 2013.

I have the following code

class Foo{
public:
     Foo(){};
     Foo* fPtr;
     float f;
};

int main()
{
    Foo foo1; // No Warning. fPtr is initialized to NULL, f is set to 0.0.
    Foo foo2(foo1); // Compiles fine. Uses compiler generated copy constructor
    return 0;
}

Now consider the same code but without the user defined default constructor.

class Foo{
public:
               // No user defined default constructor, or equivalently
               // Foo() = default;
     Foo* fPtr;
     float f;
};

int main()
{
    Foo foo1; // Neither fPtr nor f are initialized, both contain garbage.
   //Foo foo2(foo1); // error C4700: uninitialized local variable 'foo1' used
    return 0;
}

I thought that the user defined default constructor and the implicitly defined default constructor are equivalent, but it seems to me they are not.

How exactly does the compiler defined default constructor work?

After this case, I am cautious against using compiler defined default constructors and always provide my own, even though sometimes empty default constructors. Am I misunderstanding something?

Upvotes: 1

Views: 2366

Answers (1)

songyuanyao
songyuanyao

Reputation: 173044

On implementation, the implicitly-defined default constructor does the same thing as the user-defined constructor with empty body and empty initializer list.

If the implicitly-declared default constructor is not defined as deleted, it is defined (that is, a function body is generated and compiled) by the compiler if odr-used, and it has exactly the same effect as a user-defined constructor with empty body and empty initializer list.

And

Foo foo1; // No Warning. fPtr is initialized to NULL, f is set to 0.0.

No. Not only for the 2nd code sample, even for the 1st code sample, foo1.fPtr and foo1.f are not initialized; the empty user-defined constructor doesn't initialize any members at all.

And about the compiler warning, it seems that MSVS thinks if a user-defined constructor is provided and invoked, then the object could be supposed that have been initialized. But you need to make sure that the constructor does or doesn't do what you expected.

Note that they still have some subtle different side effects; such as for list initialization and value intialization, (but not default initialization used here). e.g. for

Foo foo1{};

Then for the 1st case, the user-defined default constructor will be called; since it does nothing foo1.fPtr and foo1.f will still be uninitialized; But for the 2nd case, aggregate initialization will be performed (because of the missing of user-defined constructor), then foo1.fPtr and foo1.f will be value-initialized. i.e. foo1.fPtr is initialized to nullptr, foo1.f is initialized to 0.

Upvotes: 6

Related Questions