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.
Related
In the book I'm reading at the moment (C++ Without Fear) it says that if you don't declare a default constructor for a class, the compiler supplies one for you, which "zeroes out each data member". I've experimented with this, and I'm not seeing any zeroing -out behaviour. I also can't find anything that mentions this on Google. Is this just an error or a quirk of a specific compiler?
If you do not define a constructor, the compiler will define a default constructor for you.
Construction
The implementation of this
default constructor is:
default construct the base class (if the base class does not have a default constructor, this is a compilation failure)
default construct each member variable in the order of declaration. (If a member does not have a default constructor, this is a compilation failure).
Note:
The POD data (int,float,pointer, etc.) do not have an explicit constructor but the default action is to do nothing (in the vane of C++ philosophy; we do not want to pay for something unless we explicitly ask for it).
Copy
If no destructor/copy Constructor/Copy Assignment operator is defined the compiler builds one of those for you (so a class always has a destructor/Copy Constructor/Assignment Operator (unless you cheat and explicitly declare one but don't define it)).
The default implementation is:
Destructor:
If user-defined destructor is defined, execute the code provided.
Call the destructor of each member in reverse order of declaration
Call the destructor of the base class.
Copy Constructor:
Call the Base class Copy Constructor.
Call the copy constructor for each member variable in the order of declaration.
Copy Assignment Operator:
Call the base class assignment operator
Call the copy assignment operator of each member variable in the order of declaration.
Return a reference to this.
Note Copy Construction/Assignment operator of POD Data is just copying the data (Hence the shallow copy problem associated with RAW pointers).
Move
If no destructor/copy Constructor/Copy Assignment/Move Constructor/Move Assignment operator is defined the compiler builds the move operators for you one of those for you.
The default implementation is:
Implicitly-declared move constructor
If no user-defined move constructors are provided for a class type (struct, class, or union), and all of the following is true:
Move Constructor:
Call the Base class Copy Constructor.
Call the move constructor for each member variable in the order of declaration.
Move Assignment Operator:
Call the base class assignment operator
Call the move assignment operator of each member variable in the order of declaration.
Return a reference to this.
I think it's worth pointing out that the default constructor will only be created by the compiler if you provide no constructor whatsoever. That means if you only provide one constructor that takes an argument, the compiler will not create the default no-arg constructor for you.
The zeroing-out behavior that your book talks about is probably specific to a particular compiler. I've always assumed that it can vary and that you should explicitly initialize any data members.
Does the compiler automatically generate a default constructor?
Does the implicitly generated default constructor perform zero
initialization?
If you legalistically parse the language of the 2003 standard, then the answers are yes, and no. However, this isn't the whole story because unlike a user-defined default constructor, an implicitly defined default constructor is not always used when creating an object from scratch -- there are two other scenarios: no construction and member-wise value-initialization.
The "no construction" case is really just a technicality because it is functionally no different than calling the trivial default constructor. The other case is more interesting: member-wise value-initialization is invoked by using "()" [as if explicitly invoking a constructor that has no arguments] and it bypasses what is technically referred to as the default constructor. Instead it recursively performs value-initialization on each data member, and for primitive data types, this ultimately resolves to zero-initialization.
So in effect, the compiler provides two different implicitly defined default constructors. One of which does perform zero initialization of primitive member data and the other of which does not. Here are some examples of how you can invoke each type of constructor:
MyClass a; // default-construction or no construction
MyClass b = MyClass(); // member-wise value-initialization
and
new MyClass; // default-construction or no construction
new MyClass(); // member-wise value-initialization
Note: If a user-declared default constructor does exist, then member-wise value-initialization simply calls that and stops.
Here's a somewhat detailed breakdown of what the standard says about this...
If you don't declare a constructor, the compiler implicitly creates a default constructor [12.1-5]
The default constructor does not initialize primitive types [12.1-7]
MyClass() {} // implicitly defined constructor
If you initialize an object with "()", this does not directly invoke the default constructor. Instead, it instigates a long sequence of rules called value-initialization [8.5-7]
The net effect of value initialization is that the implicitly declared default constructor is never called. Instead, a recursive member-wise value initialization is invoked which will ultimately zero-initialize any primitive members and calls the default constructor on any members which have a user-declared constructor [8.5-5]
Value-initialization applies even to primitive types -- they will be zero-initialized. [8.5-5]
int a = int(); // equivalent to int a = 0;
All of this is really moot for most purposes. The writer of a class cannot generally assume that data members will be zeroed out during an implicit initialization sequence -- so any self-managing class should define its own constructor if it has any primitive data members that require initialization.
So when does this matter?
There may be circumstances where generic code wants to force initialization of unknown types. Value-initialization provides a way to do this. Just remember that implicit zero-initialization does not occur if the user has provided a constructor.
By default, data contained by std::vector is value-initialized. This can prevent memory debuggers from identifying logic errors associated with otherwise uninitialized memory buffers.
vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
Entire arrays of primitives type or "plain-old-data" (POD)-type structures can be zero-initialized by using value-initialization syntax.
new int[100]();
This post has more details about variations between versions of the standard, and it also notes a case where the standard is applied differently in major compilers.
C++ does generate a default constructor but only if you don't provide one of your own. The standard says nothing about zeroing out data members. By default when you first construct any object, they're undefined.
This might be confusing because most of the C++ primitive types DO have default "constructors" that init them to zero (int(), bool(), double(), long(), etc.), but the compiler doesn't call them to init POD members like it does for object members.
It's worth noting that the STL does use these constructors to default-construct the contents of containers that hold primitive types. You can take a look at this question for more details on how things in STL containers get inited.
The default constructor created for a class will not initialize built-in types, but it will call the default constructor on all user-defined members:
class Foo
{
public:
int x;
Foo() : x(1) {}
};
class Bar
{
public:
int y;
Foo f;
Foo *fp;
};
int main()
{
Bar b1;
ASSERT(b1.f.x == 1);
// We know nothing about what b1.y is set to, or what b1.fp is set to.
// The class members' initialization parallels normal stack initialization.
int y;
Foo f;
Foo *fp;
ASSERT(f.x == 1);
// We know nothing about what y is set to, or what fp is set to.
}
The compiler will generate default constructors and destructors if user-created ones are not present. These will NOT modify the state of any data members.
In C++ (and C) the contents of any allocated data is not guaranteed. In debug configurations some platforms will set this to a known value (e.g. 0xFEFEFEFE) to help identify bugs, but this should not be relied upon.
Zero-ing out only occurs for globals. So if your object is declared in the global scope, its members will be zero-ed out:
class Blah
{
public:
int x;
int y;
};
Blah global;
int main(int argc, char **argv) {
Blah local;
cout<<global.x<<endl; // will be 0
cout<<local.x<<endl; // will be random
}
C++ does not guarantee zeroing out memory. Java and C# do (in a manner of speaking).
Some compilers might, but don't depend on that.
In C++11, a default constructor generated by the compiler is marked deleted , if :
the class has a reference field
or a const field without a user-defined default constructor
or a field without a default initializer, with a deleted default constructor
http://en.cppreference.com/w/cpp/language/default_constructor
C++ generates a default constructor. If needed (determined at compile time I believe), it will also generate a default copy constructor and a default assignment constructor. I haven't heard anything about guarantees for zeroing memory though.
The compiler by default will not be generating the default constructor unless the implementation does not require one .
So , basically the constructor has to be a non-trivial constructor.
For constructor to be non-trivial constructor, following are the conditions in which any one can suffice:
1) The class has a virtual member function.
2) Class member sub-objects or base classes have non-trivial constructors.
3) A class has virtual inheritance hierarchy.
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).
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)
Lets say I have this class:
class X {
public:
int x;
};
I saw that if I create an instance of X locally, x will not be initialize to 0, only if I create it globally.
Does this mean that the default constructor isn't synthesized by the compiler(I doubt it) for objects created localy or it will be synthesized but not zero out x value, if this is the case why is that ?
Constructors in C++ don't generally initialize members to 0. You have to explicitly initialize members with a value.
The reason that in the global case the memory is zero, is because static memory gets initialized to zero before anything else happens to it. In your case, the implicitly generated default constructor gets called afterwards, which does not touch the memory for member X.
See also this answer from Derek: Is global memory initialized in C++?
Note, however, that default constructors for structured, non-POD members (classes and structs) do automatically get called by the default constructor. It's just the POD members that are left alone by default.
X gets a synthesised constructor, but synthesised constructors do not zero-initialise primitives.
You are combining the concept of object construction with member initialization. As a general rule, don't expect C++ to initialize primitive data members for you, you'll need to do that yourself (preferably via an initialization list after the constructor.)
This is primarily for speed, as this allows allocation without initialization, which is useful if, for instance, you will be computing the values of the data members later and overwriting any "default" values.
I've found this site a useful reference in the past: http://www.cplusplus.com/doc/tutorial/variables/
Default constructors are not aware that it should initialize your member variables. If you need to initialize x to something, you better add your own constructor to do this for you:
class X {
public:
X() : x(0) { };
int x;
};