3

I found some answers for this question regarding java but nothing specifically regarding c++. So I've read in Java the object is first created and then the constructor is called. I was wondering if this was the same process for c++? Also, if this is the case, then what's the point of having a default constructor at all? Is it for inheritance purposes?

Jason
  • 2,198
  • 3
  • 23
  • 59
  • Are you asking when during an objects *lifetime* is the constructor called for it? – NathanOliver Dec 21 '15 at 16:22
  • I suppose, yes. I guess I was trying to wrap my head around why a constructor that takes no parameters and has no implementation defined for it would be used at all. Just want to understand why a constructor must be there in the first place. – Jason Dec 21 '15 at 16:42
  • It is used to indicate that "nothing to do here" (assuming that is what you want - otherwise, you should supply your own constructor that does the right thing - or `= delete` the constructor so that the object can not be default constructed, if that's what you actually want to have happen) – Mats Petersson Dec 21 '15 at 16:47
  • @Jason A constructor with an empty body will still default initialize members. – curiousguy Dec 21 '15 at 17:03
  • Okay, so does it default initialize them to zero or null? – Jason Dec 21 '15 at 17:12
  • There's also the possibility that the compiler can eliminate the call to the constructor almost entirely, if it has no parameters and and empty body ("no implementation.") That doesn't eliminate the initialization step (vtables, runtime-dependent stuff), but it does allow the compiler to elide constructors together. – scooter me fecit Dec 21 '15 at 17:35
  • @Jason The default initialization calls the default constructor of every member. It doesn't write zero or null. – curiousguy Dec 21 '15 at 21:15

9 Answers9

8

"Object creation" means different things in different languages. But in C++ the most salient question is "when does the object lifetime begin". When an object's lifetime has begun, that means that when it later ends (you delete it, or if it is a stack object, then when it goes out of scope), the destructor will be called.

If the object's lifetime did not formally begin, then if it goes out of scope later, the destructor will not be called.

C++ resolves this as follows:

  • When you make an object, say of class type, by invoking a constructor, first the memory is allocated, then the constructor runs.
  • When the constructor runs to completion, then the lifetime has begun, and the destructor will be called when it ends. After the destructor finishes, the memory will be freed.
  • If the constructor aborts, say, by throwing an exception, then the destructor for that object will not be called. The memory will still be freed, however.

For more info on object lifetimes you might want to look at e.g. this question, or better, at the standard / a good text book.

The basic idea is that, in C++, we try to minimize the window of time between when the memory has been allocated and when it is initialized -- or rather, the language itself promotes the idea that "resource acquisition is initialization" and makes it un-idiomatic to acquire memory without also giving it a type and initializing it. When typically writing code, e.g. if you have a variable of type A, you can think of it as "This refers to a block of memory for an A, where a constructor for A successfully ran to completion." You don't normally have to consider the possibility that "this is a block of memory the size of an A, but the constructor failed and now its an uninitialized / partially initialized headless blob."

Community
  • 1
  • 1
Chris Beck
  • 15,614
  • 4
  • 51
  • 87
  • Your answer says `If the object's lifetime did not formally begin, then if it goes out of scope later, the destructor will not be called.` What does it mean when you say that the object's lifetime does not formally begin and ends due to program execution going out of scope? I mean, you said an object is destroyed even before its lifetime begins? How can it happen? – asn Jul 25 '19 at 17:59
  • 1
    Suppose that we have `class A { B b; C c; D d; };` In *any* constructor for `A`, each of the members `b, c, d` will be initialized, in that order. Even if it is the default constructor, this will result in calls to default constructor for `b`, `c`, `d`. If an exception is thrown during construction of member `c`, then the destructor `~B` will be called at member `b`, but destructor for `C`, `D`, `A` will not, because those objects did not get to finish being constructed yet, so it would not make sense to call their destructors. – Chris Beck Jul 25 '19 at 21:22
  • Yes, that truly makes sense. – asn Jul 26 '19 at 04:29
2

It depends on what you mean by "created". Obviously memory should be allocated before object can be created.

But officially, object is not created (its lifetime is not started) until after constructor finishes execution. If constructor did not execute completely (exception happened, for example), object is considered never existing in first place. For example destructor for this object will not be called (as it would for any existing object)

When you enter constructor body, you can be sure that members are create (either by default constructors or whatever was passed in constructor initializer list; usual language rules for variable initialization applies: initial values of scalar variables are undefined).

When you consider inheritance, it is even more complex. When you enter constructor body, ancestors parts are already existing objects: their constructor had finished, and even if children would not be able to construct itself properly, their destructors will be called.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48
  • "_you can be sure that members are initialized_" For scalar types, this guaranteed initialization is no initialization at all. – curiousguy Dec 21 '15 at 21:13
  • @curiousguy, probably better word would be "created". And undefined initial values for scalar type worth mentioning too. – Revolver_Ocelot Dec 21 '15 at 21:18
1

Neither.

The process of object creation includes a constructor call.

The point of having a default constructor is to allow this part of the object creation process to be a no-op. What else would it be?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

Here's the sequence: first, memory is allocated. Then any base class constructors are called. Finally the class constructor is called.

You don't actually need a default constructor if you'll always create your objects with a parameter list.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
1

You seem to be confusing terms but I'll try to define some (unofficial) terms that should clarify this issue:

  1. Allocation
    This is the step where memory is allocated for the object.
  2. Initialization
    This is the step where the language related object properties are "set". The vTable and any other "language implementation" related operations are done.
  3. Construction
    Now that an object is allocated and initialized, the constructor is being executed. Whether the default constructor is used or not depends on how the object was created.

You can consider an object created after the 3rd step.

Amit
  • 45,440
  • 9
  • 78
  • 110
  • Okay I see, ya maybe I wasn't clear enough with my terms. Thank you. I guess my main thing was trying to figure out the point of having a constructor with no implementation and no parameters as is the case with compiler created constructors. – Jason Dec 21 '15 at 16:45
  • Initialization is part done by the constructor, it's part of construction. – curiousguy Dec 21 '15 at 21:08
  • @curiousguy - I specifically wrote that this terms are **not** official, I used them here to make a point. The initialization part I refer to is implicit language related operations that happen before first line of constructor code. – Amit Dec 21 '15 at 22:45
  • I am OK with unofficial term, but this presentation is misleading: "_Now that an object is allocated and initialized, the constructor is being executed_" Also the first line of the constructor in not the body in the general case, it's the ctor init list. – curiousguy Dec 22 '15 at 03:47
  • @curiousguy - that's nitpicking at best I don't find any of that crucial for the scope of this answer, but here's an idea: if you see some inaccuracy in an answer, why not try to improve it with an edit instead of thrashing and downvoting? what's more important to you a downvote, or helping the community (aka future readers)? – Amit Dec 22 '15 at 06:46
  • @Amit I won't edit another answer except for obvious typos, grammar, etc. And I believe this "nitpicking" **is** crucial for understanding C++. Maybe not a trivial case of a class with no bases, but if you are using virtual functions, you will certainly have base classes at some point and you need to understand the construction of derived classes. – curiousguy Dec 22 '15 at 15:55
0

Yes, the object's memory is first allocated, then the constructor called to actually construct the content. A bit like building a house, you first purchase [or otherwise legally get permission] the land (memory) to build it on, then start building. If you do it the other way around, you're likely to get into trouble.

A default constructor is used when your object needs to be constructed with no parameters. In some cases, this doesn't make any sense at all, but default constructors are used for example in the std::vector - since a std::vector<myclass> will be implemented as an array of objects, and if you grow it [using push_back], the size will double (or something like it), and the objects at the back of the vector that hasn't been used will be default constructed.

All objects need to be constructed after creation (even if you don't declare one, in which case you get an empty constructor, and if the compiler is clever it will not call the constructor because it doesn't do anything)

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • You might want to get rid of the vector size doubling when growing the capacity of the vector as MSVS uses 1.5 instead of 2 like libstdc++ – NathanOliver Dec 21 '15 at 16:26
  • @NathanOliver: How does that allow for amortized growth of O(1)? [Text fixed to reflect that it's not guaranteed to 2.0 multiplier] – Mats Petersson Dec 21 '15 at 16:41
  • I am not sure if it qualifies of amortized O(1) growth or not but see: http://stackoverflow.com/questions/5232198/about-vectors-growth – NathanOliver Dec 21 '15 at 16:43
  • 1
    Err, doesn't any factor `>1` allow amortized constant growth? `O(C * n / n) = O(C) = O(1)`. Or am I missing something? – eerorika Dec 21 '15 at 16:46
  • @user2079303: I seem to remember that discussion happening here, and I claimed something - could be that it was somewhere else, but I wrote some code to count and grow with other factors, and I think you have to grow by at least 2 to get O(1) amortized. But it could be something else I was thinking of. – Mats Petersson Dec 21 '15 at 16:50
  • @MatsPetersson The factor 2 growth was just something in the original HP STL code, not a requirement. – curiousguy Dec 22 '15 at 15:55
0

The term "default constructor" just means a constructor that needs no parameters, such that it can be used by-default. For example:

struct MyObject {
    MyObject() { ... }    // default constructor
    MyObject(int) { ... } // some other non-default constructor
};

int main()
{
    MyObject x;  // default constructor is called since you didn't give
                 // any explicit parameters.
    MyObject x2(5); // A non-default constructor is called.
}

Note that the term "default" doesn't mean that you haven't defined it. The default constructor may be provided by you or it may be automatically generated in certain situations. You even have the case of the defaulted default constructor:

struct MyObject {
    MyObject() = default; // defaulted default constructor
};

Here, you've told the compiler to generate a default constructor using the default implementation.

Regardless of whether it is a default constructor or not, the object has been constructed as much as automatically possible before the constructor body is executed. This means the memory has been allocated to store the object, any base classes have been constructed, and any members have been constructed. The object also has taken the type identity of the class being constructed for purposes of RTTI and virtual function calls.

Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
  • Okay, I guess in my mind a default constructor also involved no implementation details. But you're saying it just means no parameters are being taken? – Jason Dec 21 '15 at 16:37
  • @Jason: That's right. It's a fairly common misunderstanding. The term "default" is used in the sense of "Which constructor am I going to call if you didn't explicitly say which constructor to call? Answer: the default constructor." – Vaughn Cato Dec 21 '15 at 16:40
0

Also, if this is the case, then what's the point of having a default constructor at all?

The point of "Default Constructor" is to tell the program how objects with no parameters should be built, in other words - what is the "default" state of an Object.

for example, the default state of std::unique_ptr is to point to null with no costume deleter.
The default state of a string is an empty string with the size of 0.
The default state of a vector is an empty vector with the size of 0.
The default state of T is the one specified by the constructor T().

David Haim
  • 25,446
  • 3
  • 44
  • 78
  • Ya, I think, as pointed out to me by others, I was confusing the term "default constructor". What I really wanted to know was what the point was of having the compiler create a constructor with no implementation. Why go through the trouble of creating something that does nothing? – Jason Dec 21 '15 at 16:52
  • it calls inner objects constructor, if there are any. for example , if your object contains a string, default constructor will call that strign constructor, even if its empty. – David Haim Dec 21 '15 at 16:54
  • `int()` is 0, but a default initialized `int` member is not initialized. – curiousguy Dec 21 '15 at 17:05
0

Think that constructor has to be called after object's creation due to resource allocation issues. An object is no more than a structure with functions pointers (members function) and member variables (attributes). An error would occur if the constructor sets up any of these values before they are allocated in memory.

For example, your constructor stores an int value in a member variable of your object, but your object's member variables haven't been allocated, so the value cannot be stored successfully.

Regards!

kub0x
  • 159
  • 1
  • 7