From Thinking in C++
The first hidden argument to the constructor is the this pointer. this pointer holds the address of the caller object. In the case of constructor this pointer points towards an uninitialized block of memory. It is the job of the constructor to initialize this block of memory properly.
So, basically, the constructor is used to get a pointer to the object's space in RAM? Is that correct?
How does the default constructor initialize that memory? Does it get initialized to zero?
The role of the default constructor is the same as any other constructor: To initialize the object. The default constructor (or a constructor with only default arguments) sets member variables to a known state, like setting pointers to nullptr (or 0), etc.
Lets say we have this structure:
struct Foo
{
int a;
int* b;
// Default constructor
// Set `a` to `1`, and `b` to `nullptr`
Foo() : a(1), b(nullptr) {}
};
Now when you declare an instance of the Foo class, then you know what state the member variables will have. If there wasn't a constructor, a normal local variable instance of the Foo class would have undefined values for the a and b members.
If you don't provide a constructor at all, default or other, then the compiler will make a default constructor for you (one is needed, or you would not be able to create instances of the classes), but it will not do any initialization of members.
The hidden argument talked about, is the variable known as this, and it exists for all member functions which are not static.
So, basically, the constructor is used to get a pointer to the object's space in RAM? Is that correct?
No, the constructor is not used to get a pointer.
The purpose of the constructor is to initialize all member variables when an object of this class is created. It initializes the object in memory.
The default constructor is the constructor that can be called with no arguments.
When you implement a class, you can implement your own default constructor to make it do what you want it to do.
When you do not provide any constructor for your class, the compiler will provide a default constructor for this class, but it will not initialize the members.
Default constructors are significant because they are automatically invoked in certain circumstances:
When an object value is declared with no argument list, e.g. MyClass x;; or allocated dynamically with no argument list, e.g. new MyClass or new MyClass(); the default constructor is used to initialize the object
When an array of objects is declared, e.g. MyClass x[10]; or allocated dynamically, e.g. new MyClass [10]; the default constructor is used to initialize all the elements
When a derived class constructor does not explicitly call the base class constructor in its initializer list, the default constructor for the base class is called
When a class constructor does not explicitly call the constructor of one of its object-valued fields in its initializer list, the default constructor for the field's class is called
In the standard library, certain containers "fill in" values using the default constructor when the value is not given explicitly, e.g. vector<MyClass>(10); initializes the vector with 10 elements, which are filled with the default-constructed value of our type.
In the above circumstances, it is an error if the class does not have a default constructor.
No. The constructor is not used to get a pointer. The constructor receives this pointer.
The constructor is used to initialize the object's space in RAM.
The default constructor does what you want it to do! I mean your can write your own default constructor for your class. This default constructor can initialize the memory, or leave it uninitialized, as you choose.
In the same vein, the implicit default constructor will be written automatically by the compiler to initialize the object RAM space. It will take care of initializing the non-static member variables of your class that do have default constructors. For example, if your class has a non-static std::string as member variable, then std::string default constructor will be called to initialize this variable. All non-static member variables of POD types (int, char, pointers,...) will not be initialized.
No.
MyClass obj; // Default construct
MyClass* obj2 = new MyClass; // Also default construct
In the first one, space for obj is first allocated, typically in the stack. The second one is allocated on the heap. The addresses where they reside are the ones that are passed to the proper constructor in these case.
The first-argument-is-the-this-pointer situation does not only apply to the default constructor, as a hidden this pointer is passed to all non-static class methods as their first arguments[1].
Then you probably know the rest. The constructor sets-up and initializes the object's members and states and any other things that needs to be done.
[1]Have you observed some examples like this?
my_type obj;
func_that_calls_a_callback(std::bind(&my_type::method, &obj));
That demonstrates that the first parameter is a pointer to some object is bound to the first parameter of my_type::method. That becomes the this pointer which points, in this case, to obj.
So, basically, the constructor is used to get a pointer to the object's space in RAM? Is that correct?
No, that's just a consequence
How does the default constructor initialize that memory? Does it get initialized to zero?"
No: the default constructor is just a function. It does what what you define it to do.
It is normally designed to "initialize" the memory by assigning to the contained variables (the object member) a proper value or by calling in turn their own constructors.
Think to this:
class point
{
public:
int x,y; //< just two values
point() //< default constructor
{ x=0; y=0; } //< function body assigning values
};
or
class point
{
public:
int x,y; //< just two values
point() //< default constructor
:x(), y() //< member init-list explicitly calling contrutors
{} //< empty body
};
Note that, until you don't declare a variable of type point nothing will be executed.
int main()
{
point p; //< p created and point::point() called using p as *this
p.x=5; //< x member of p changed
return 0; //just exit main (jumps to the closing } )
} //< p destructor called here, using p as *this.
As per the "implicit default constructor", what it does is just:
call the bases implicit default constuctors
call the members implicit
default contructors.
For all class-based types, decaring a default ctor in fact replaces the implicit one, but -for "built-in types" (like int, char, float etc.)- the default explicit constructor -in fact- sets the value to zero, but the implicit one does nothing, thus letting the value uninitialized. (the implementations can use different techniques to come to this same result)
Related
So if I have something like the following:
class MyClass{
public:
MyClass(){
// do other stuff
*oc = OtherClass(params);
}
private:
OtherClass* oc;
}
When is a constructor called on OtherClass? Would its default be called once as soon as the MyClass initialization begins, and then be redefined with its value constructor during the MyClass constructor? Or does it just not exist during "//do other stuff". What if no default constructor is provided for other class, only a value? Would it be good practice to construct it where it is defined as a member variable?
A default constructor is one that can be called without parameters. For example this is a default constructor:
struct foo {
foo(){} // (should not actually be user defined)
};
This is also a default constructor:
struct bar {
bar(int x = 42) {}
};
In your code it might be that the constructor that is called is a default constructor, but it does not matter for your code, because you do pass a parameter.
When is a constructor called on OtherClass?
In the line *oc = OtherClass(params);.
Would its default be called once as soon as the MyClass initialization begins, and then be redefined with its value constructor during the MyClass constructor?
If you do not provide an initializer members are default initialized. Confusingly for a pointer this means it is not initialized.
Or does it just not exist during "//do other stuff".
The member does exist before, but its value is indeterminate. You cannot use the value without invoking undefined behavior.
What if no default constructor is provided for other class, only a value?
See above. The existance of a default constructor of OtherClass is not relavant here. It would be relevant if the member was OtherClass and not a pointer, because for members of class type default initialization calls the default constructor.
Would it be good practice to construct it where it is defined as a member variable?
It is good practice to provide an initializer for members rather than assign in the constructor:
class MyClass{
public:
MyClass() : oc(params) {
}
private:
OtherClass oc;
}
I replaced the member with an instance rather than a pointer, because using a raw pointer as member opens up a can of worms that would require an even longer answer. For more on that read What is The Rule of Three?. Note that when the member is not a pointer but a OtherClass then suddenly it matters if OtherClass has a default constructor, because if you do not provide an initializer, then the member will be default constructed. Though in the above I used the member initializer list and the member will be initialized by the constructor that takes one parameter.
ÓtherClass *oc; is a pointer and as such has no constructor. It has to be initialized to a valid object before you can dereference it.
You can ensure oc is initialized by, well, initializing it:
MyClass() : oc(new OtherClass()) {
...
*oc = OtherClass(params);
}
This will create a dummy oc when the class it created and then copy or move assign the real object to *oc later. This is wasteful, so why not initialize it with the final value directly:
MyClass() : oc(new OtherClass(params)) {
...
}
or if you have to compute params first:
MyClass : oc(nullptr) {
...
oc = new OtherClass(params);
}
Initializing oc with nullptr first isn't required but it is dirt cheap and it ensures accidentally using oc will access a nullptr and fail instead of oc being some random value that might not crash.
You can also, and better, ensure initialization by inlineing that:
class MyClass {
...
private:
OtherClass *oc(nullptr);
}
With that the compiler will initialize oc whenever you don't initialize it in an initializer list in the constructor.
That said: Do you really need a pointer there? You need a destructor, copy/move constructors and aissgnment operators to handle the pointer directly. An Otherclass oc; would be much easier to deal with.
But if you do need a pointer then you should use a smart pointer to handle ownership for you. That means use std::unique_ptr or more likely std::shared_ptr for it. You might not even need anything past the constructor that way. But think about what it means for copy/move to have the pointer shared. Read about the rule of 0/3/5.
I have searched previous questions, and have not found a satisfying answer to my question:
If I define an empty default constructor for a class, as for example
class my_class{
public:
myclass(){}
private:
int a;
int* b;
std::vector<int> c;
}
my understanding is that if I define an object using the default constructor, say
my_class my_object;
then my_object.a will be a random value, the pointer my_object.b will also be a random value, however the vector c will be a well-behaved, empty vector.
In other words, the default constructor of c is called while the default constructors of a and b is not. Am I understanding this correctly? What is the reason for this?
Thank you!
a and b have non-class types, meaning that they have no constructors at all. Otherwise, your description is correct: my_object.a and my_object.b will have indeterminate values, while my_object.c will be properly constructed.
As for why... by writing a user-defined constructor and not mentioning a and b in the initializer list (and not using C++11 in-class member initializers) you explicitly asked the compiler to leave these members uninitialized.
Note that if your class did not have a user-defined constructor, you'd be able to control the initial values of my_object.a and my_object.b from outside, by specifying initializers at the point of object declaration
my_class my_object1;
// Garbage in `my_object1.a` and `my_object1.b`
my_class my_object2{};
// Zero in `my_object2.a` and null pointer in `my_object2.b`
But when you wrote your own default constructor, you effectively told the compiler that you want to "override" this initialization behavior and do everything yourself.
Since a and b are not objects but primitive datatypes, there is no constructor to call. In contrast, c is an object, so its default constructor is called.
#include<iostream>
using namespace std;
class A {
public:
int i;
};
int main() {
const A aa; //This is wrong, I can't compile it! The implicitly-defined constructor does not initialize ‘int A::i’
}
when I use
class A {
public:
A() {}
int i;
};
this is ok! I can compile it! why I can't compile it when I use the implicitly-defined constructor?
why the implicit-defined constructor does not work?
It does work, but one of the language rules is that it can't be used to initialise a const object unless it initialises all the members; and it doesn't initialise members with trivial types like int. That usually makes sense, since being const there's no way to give them a value later.
(That's a slight simplification; see the comments for chapter and verse from the language standard.)
If you define your own constructor, then you're saying that you know what you're doing and don't want that member initialised. The compiler will let you use that even for a const object.
If you want to set it to zero, then you could value-initialise the object:
const A aa {}; // C++11 or later
const A aa = A(); // historic C++
If you want to set it to another value, or set it to zero without the user having to specify value-initialisation, then you'll need a constructor that initialises the member:
A() : i(whatever) {}
why the implicit-defined constructor does not work?
Because the C++ standard says so:
[dcl.init] paragraph 7:
If a program calls for the default initialization of an object of a const-qualified type T, T shall be a class type with a user-provided default constructor.
This ensures that you don't create a const object containing uninitialized data that cannot be initialized later.
To initialize a const-qualified object you need to have a user-provided default constructor or use an initialiser:
const A aa = A();
Here the object aa is initialized with the expression A() which is a value-initialized object. You can value-initialize a class type without a default constructor, because value-initialization will set values to zero if there is no default constructor for the type.
However, the rule in the standard is too strict, as it forbids using implicitly-defined constructors even when there are no data members or all data members have sensible default constructors, so there is a defect report against the standard proposing to change it, see issue 253.
You don't state what compiler you're using. I've tried this with VS2012 and get a warning C4269.
The reason this is a problem is because aa is const. Because you haven't defined a constructor a default one is used and so i can be anything. It also cannot be changed (because aa is const).
If you define a constructor, it is assumed that you are happy with the initialization of i. Although, in this case you haven't actually changed the behaviour.
From this MSDN page
Since this instance of the class is generated on the stack, the initial value of m_data can be anything. Also, since it is a const instance, the value of m_data can never be changed.
Because i is not initialized.
class A
{
public:
A()
{
i =0;
}
int i;
};
"Implicit constructor" means a constructor generated for you automatically and generates an error because it realizes it is not able to initialize the value of i. This can be a no-args constructor, a copy constructor or (as of C++11) a move constructor.
why the implicit-defined constructor does not work?
It works just fine, but it does not decide what your default values are implicitly (and as such, it only calls default constructors for it's members, but not for POD types).
If you want the constructor to initialize your members with certain values you have to explicitly write that (i.e. add a default constructor explicitly).
Making a default (implicit) constructor initialize POD members with a chosen value (like zero for example) would add extra computing cycles (and slow your program down) when you don't need that. C++ is designed to behave as if you (the programmer) know what you are doing (i.e. if you do not initialize your members explicitly, the compiler assumes you don't care what default value you get).
When I declare a an array, all the variables/objects get declared. But what happens with the objects, if their class has constructors? The class I'm using has 2 constructors - one with no arguments and one with a few arguments. Will the first constructor activate after the declaration? Or no constructors will activate?
If the first case happens, I'll have to make a function that replaces the constructors.
So, what happens with the objects in a newly declared array?
It depends how you declare the array. The members will be either default, value, or copy-initialized:
Foo x[] = { Foo(1), Foo(true, 'a'), Foo() }; // copy-initialize
Foo x[3] = { }; // value-initialize
Foo x[3]; // default-initialize
For class types, default- and value-initialization call the default constructor. Copy-initialization may call the appropriate constructor directly.
If you don't want to use the default-constructor, you won't get arround the brace-initializer and spelling out each member.
Arrays will invoke the default constructors on all objects if the underlying type has a non-trivial default constructor.
I don't remember the rules exactly, but ints, char*s, structs whose members all have trivial constructors, etc., all have trivial default constructors. Arrays of these things (and arrays of arrays of these things, etc.) won't be initialised unless you do so explicitly.
An explicitly declared default constructor is never trivial, so the Foo objects in your array will be default-constructed.
I have a global member data object, defined in a header (for class MyMainObj) like this.
class MyMainObj
{
MyDataObj obj;
}
MyDataObj has a default constructor.
When is the constructor for MyDataObj called?
Is it called as part of the creation of MyMainObj?
MyDataObj in this case is not a member of MyMainObj, it's a local variable.
But, constructors for data members are called in your class's constructor. The default constructor for every member is called before execution reaches the first line in the constructor, unless you explicitly specify a constructor using an initializer list, in which case that constructor is called instead.
With that code, obj isn't a member of MyMainObj -- it's simply a local object inside that constructor. As such, it'll only be constructed when/if that constructor is invoked.
Concerning your code, you have a function with a variable inside. Upon entering the function, you will run to the line of code that declares the variable, and the constructor will be run then.
But you say "creation of MyMainObj". It's a function, it can only be called, not created.
This is all concerning the title question, "when are members constructed?" This would apply if MyMainObj was a class and not a function.
Your member objects are constructed in the order of which they appear in the class declaration. All objects are full constructed upon entering the constructor. (But this does not include the class itself!)
That is to say, by the time the class enters its constructor, all the members have finished their constructor.
Objects are destructed in reverse order, in the destructor (after the destructor is run).
In a pseudo-diagram:
MyClass
Member1
Member2
Member3
Construction:
Member1
Member2
Member3
MyClass
Destruction:
MyClass
Member3
Member2
Member1
You can manually call the members constructor using an initialization list:
class foo
{
public:
foo(void) : i(0) // construct i with 0.
{
}
int i;
};
There are various question on SO about initialization lists. Initialization list order, Copy-construction initialization list, and more.
Yes, the constructor would be called whenever a MyMainObj instance is created.
I'm a bit confused by the "global member" terminology - the way you've declared that object it would be a local variable inside the constructor. Am I missing something here?
Yes, as other stated the member will be created on the owner class creation, on construction (be it generated by the compiler or with a provided constructor).
The order of creation will be the same as how your members apear in the class declaration. For example :
class MyType
{
Thing a;
Thing b;
Thing d;
Thing c;
};
Whatever constructor is used, whatever the order in a initialization list, the members will be constructed in this order : a, b, d, c. Once it's all done, the constructor code will be executed (if it exists) and only then your whole object will be constructed.
Upon entering an object constructor, memory has already been allocated for it. Then the execution order is as follows:
Base class constructor, if any, as specified in the initialisation list; if not specified, the default constructor is used.
The constructors for the member data, as specified in the initalisation list (default if not specified), in the order they are declared in the class definition. The order in which they are specified in the initialisation list is irrelevant.
The constructor body.
In the example set in the question, the first thing that would be executed upon entering the default constructor of MyMainObj would be the default constructor of MyDataObj to construct the member data obj.
Given a class A:
class A {
MyDataObj obj;
}
If you don't write the constructor for A, the compiler will create one for you, which will create obj as part of constructing A (and destroy obj as part of destroying A.
If you do write a constructor for A, then obj will be created before your constructor runs, although you can reassign it:
class A {
MyDataObj obj;
public:
A() { } // obj created, but the value may or may not be predictable
}
class AA {
MyDataObj obj;
public:
AA()
{
obj = MyDataObj(5);
}
}
class AAA {
MyDataObj obj;
public:
AAA() : obj(5) { } // member initializer list, my preferred method
}
With the third option, the data objects are created before the member initializer list runs, and the values are assigned in the order they are declared in AAA, NOT the order they are listed in the member initializer list.
UPDATE: There is a difference between creation and initialization. Space for the data members (and the base classes, and the data members for the base classes) is always set aside -- which I would call "creation." However, that doesn't mean a useful value is stored in that memory. There are separate rules for whether an object is default initialized, which depend on the type of the data member (primitive, POD, non-POD) and, IIRC, the storage class of the main object (local, static, global). The easiest way to avoid surprises in this area is to simply make sure you explicitly initialize everything.