1

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?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Hrachya_h
  • 11
  • 2
  • 3

1 Answers1

6

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.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • I do not quite understand what you mean by "No. Even for the 1st code sample, foo1.fPtr and foo1.f are not initialized; the user-defined constructor does nothing in fact.". The fact is that in the first case the user defined constructor is called both with `Foo foo1;` and `Foo foo1{}` and the members are correctly initialized to their default values, i.e. NULL and 0.0, so I assume the user defined constructor indeed does something. – Hrachya_h Mar 10 '17 at 05:15
  • 2
    @Hrachya_h No, they're not initialized, for example http://rextester.com/JVFH58493. – songyuanyao Mar 10 '17 at 05:23
  • 1
    `Foo foo1;` DOES NOT initialize the members in both examples, due to lack of any initialization. If they are getting initialized to zeros, it is random undefined behavior by the compiler. It is NOT guaranteed in these examples. – Remy Lebeau Mar 10 '17 at 05:45
  • "The implicitly-defined default constructor does the same thing as the user-defined constructor with empty body and empty initializer list." Has that changed recently? Because it didn't use to. Value initialization with the implicitly defined constructor would zero initialize members, and do nothing in the case of a user defined constructor with empty etc etc. You seem to say as much in the last paragraph. – juanchopanza Mar 10 '17 at 06:17
  • @juanchopanza I meant for the implementation, the implicitly-defined default constructor does the same thing as the empty user-defined constructor. Yes they have different side effects for value-intialization and list-initialization(aggregate-initialization). – songyuanyao Mar 10 '17 at 06:28
  • I see. And I realise it is difficult to explain this in few words. But your leading sentence can lead one to think they are completely equivalent, so I am holding my up-vote for now ;-) Maybe if you mention that the effect is the same for *default construction* (as in OP's example) it would clarify. – juanchopanza Mar 10 '17 at 06:33
  • In Visual studio 2013 the first example initializes the members to their default values, but as you mentioned, it is not supposed to (or at least not guaranteed to). A follow up question is, why the compiler does not issue the same "C4700: uninitialized local variable" error in the first example too? Since the memberwise initialization is not guaranteed and is a "random undefined behavior", the compiler should have issued the same error. If it did not, I assume that member initialization in a user defined default (empty) constructor is a defined behavior, at least in VC 2013. – Hrachya_h Mar 10 '17 at 17:35
  • @Hrachya_h Then the compiler has to check the implementation of the user-defined constructor; whether it initializes all the members. MSVC just chooses not to do that. BTW both Gcc and Clang don't give any warning or error for both cases. – songyuanyao Mar 11 '17 at 15:12
  • @songyuanyao I used rextester and the variables were initialized as 0, so doesn't that confirm the phrase "The implicitly-defined default constructor does the same thing as the user-defined constructor with empty body and empty initializer list" ? – pitprok Jun 21 '21 at 01:39
  • @pitprok It's hard to tell that just from the initialization result. Neither the constructors initialize the data members, then as the effect of [default initialization](https://en.cppreference.com/w/cpp/language/default_initialization) `f` and `fPtr` are initialized to indeterminate values, any values are possible. – songyuanyao Jun 21 '21 at 01:53