I've started trying out the C++11 standard and i found this question which describes how to call your ctor from another ctor in the same class to avoid having a init method or the like. Now i'm trying the same thing with code that looks like this:
hpp:
class Tokenizer
{
public:
Tokenizer();
Tokenizer(std::stringstream *lines);
virtual ~Tokenizer() {};
private:
std::stringstream *lines;
};
cpp:
Tokenizer::Tokenizer()
: expected('=')
{
}
Tokenizer::Tokenizer(std::stringstream *lines)
: Tokenizer(),
lines(lines)
{
}
But this is giving me the error:
In constructor ‘config::Tokenizer::Tokenizer(std::stringstream*)’:
/path/Tokenizer.cpp:14:20: error: mem-initializer for ‘config::Tokenizer::lines’ follows constructor delegation I've tried moving the Tokenizer() part first and last in the list but that didn't help.
What's the reason behind this and how should i fix it? I've tried moving the lines(lines) to the body with this->lines = lines; instead and it works fine. But i would really like to be able to use the initializer list.
When you delegate the member initialization to another constructor, there is an assumption that the other constructor initializes the object completely, including all members (i.e. including the lines member in your example). You can't therefore initialize any of the members again.
The relevant quote from the Standard is (emphasis mine):
(§12.6.2/6) A mem-initializer-list can delegate to another constructor of the constructor’s class using any class-or-decltype that denotes the constructor’s class itself. If a mem-initializer-id designates the constructor’s class, it shall be the only mem-initializer; the constructor is a delegating constructor, and the constructor selected by the is the target constructor. [...]
You can work-around this by defining the version of the constructor that takes arguments first:
Tokenizer::Tokenizer(std::stringstream *lines)
: lines(lines)
{
}
and then define the default constructor using delegation:
Tokenizer::Tokenizer()
: Tokenizer(nullptr)
{
}
As a general rule, you should fully specify that version of the constructor that takes the largest number of arguments, and then delegate from the other versions (using the desired default values as arguments in the delegation).
Related
I am working on a program that behaves differently when I set the default constructor to when I omit it. Specifically I am building an object to pass it to a third-party library function. When I omit the default constructor, the function works as expected, however when I define it the function blocks and does not return control, so I think the problem is due to the constructor.
Below I show a summary excerpt of the part of the code that has to do with the problem.
class Config {
public:
typedef std::shared_ptr<Config> SPtr;
int frame;
int numSolidParticles = 0;
bool shapesChanged = false;
Buffer* buffer;
FlexParams params; // struct
// if omitted then the 3rd party method works as expected
Config() {
}
};
...
Config::SPtr config = std::make_shared<Config>();
initialize(config);
...
SetFlexParams(config->params);
// calls to other 3rd party methods that depends on config
...
// call 3rd party library's method that causes the issue
mapBuffer(config->buffer);
Update: What I'm trying to do is moving some of the initializations (e.g. frame, buffer and other fields not shown) in method inititalize to constructor.
What is the difference between a custom default constructor and
defaulted default constructor?
Given a class X, if: ([class.ctor]/5)
X is a union that has a variant member with a non-trivial default constructor and no variant member of X has a default member
initializer,
X is a non-union class that has a variant member M with a non-trivial default constructor and no variant member of the anonymous
union containing M has a default member initializer,
any non-static data member with no default member initializer is of reference type,
any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer does not have a
user-provided default constructor,
X is a union and all of its variant members are of const-qualified type (or array thereof),
X is a non-union class and all members of any anonymous union member are of const-qualified type (or array thereof),
any potentially constructed subobject, except for a non-static data member with a brace-or-equal-initializer, has class type M
(or array thereof) and either M has no default constructor or
overload resolution as applied to find M's corresponding constructor
results in an ambiguity or in a function that is deleted or
inaccessible from the defaulted default constructor, or
any potentially constructed subobject has a type with a destructor that is deleted or inaccessible from the defaulted default
constructor.
then the defaulted default constructor of X is defined as deleted, whereas a hand-written X() {} will be ill-formed.
Otherwise, there is no difference.
Although this does not answer the main question I would like to explain that the problem was being caused by a field of the FlexParams struct that I was forgetting to initialize.
This struct groups a large number of parameters to 3rd party library that are initialized in the initialize function. The funny thing is that when I do not define the constructor the field is initialized to 0 (which luckily was the correct value) while when I define it the field takes a random value.
The only reasonable explanation, as some of you mentioned in the comments, is that the issue was caused by undefined behavior.
Default default constructor does one thing your manual default constructor does not: it properly default-constructs the members. I'm pretty sure that if you do either of the following your code will magically start working:
Option 1: Explicitly state default values for all the members (not just the two you have done so for)
int frame = 0;
int numSolidParticles = 0;
bool shapesChanged = false;
Buffer* buffer = nullptr;
FlexParams params = {}; // struct
Option 2: Remember to initialize all non-trivially-constructible members in your constructor
Config()
: frame{0}
, numSolidParticles{0}
, shapesChanged{false}
, buffer{nullptr}
, params{} // I think this is the code generated by your compiler for the default default constructor
{
}
I personally prefer the first approach as it is clearer and way less prone to errors in a long run
I have confusion after reading from some places.
I'm doing example from this page
let's say there's a class(Book) which has an object(Author) as one of its member. Here's the constructor:
Book::Book(string name, Author author, double price, int qtyInStock)
: name(name), author(author) { **// Must use member initializer list to construct object**
// Call setters to validate price and qtyInStock
setPrice(price);
setQtyInStock(qtyInStock);
}
I tried to declare the object author inside the constructor instead of initializer lisr. It gave me error. no matching function to call Author::Author() --> which is the default constuctor of Author.
After reading from these stackoverflow posts : this1 and this2
What I understand is that, summarizing from those 2:
an object is considered & must be fully initialised when execution enters the body of the constructor
An object has all of its members initialised in the initialisation list. Even if you do not explicitly initialise them there, the compiler will happily do so for you
native types like int or double do have a default constructor
So from all of those above, what I understand is a user defined object/class DOES NOT automatically have DEFAULT CONSTRUCTOR, unlike the primitive types.
That's why it gives error, if I do not use member initializer list (which calls copy constructor) , cause the compiler tries to initialize it using default consturctor which it(user defined class) does not have.
And so possible solutions are: define a default constructor for the class, or use member initializer
AND THEN I read this post on stackoverflow saying that:
"How Many default methods does a class have?" and the answer mentions that It HAS DEFAULT CONSTRUCTOR
1. If it has default consturctor, Why does my first case( the book and author classes) give error?
Also I read from this page, lets say I defined a class Point before, then page wrote:
Point p1; // **Invoke default constructor**
// OR Point p1 = Point(); NOT Point p1();
2. So when we declare like above, does it INVOKE DEFAULT CONSTRUCTOR? Why it does not give an error if so? I thought a class does not have a default constructor?
Appreciate if you can help me to clarify things here, and answer the two questons above (italic)
The full answer is big, and is presented here:
http://en.cppreference.com/w/cpp/language/default_constructor
If you specifically make one, there is always a default constructor. This includes constructors that MAY accept parameters but don't have to - constructors with default parameters and variadic templates can both be default constructors.
If you mark it as = delete then it will never have one.
Otherwise, if no user-provided constructors are present the compiler will try to make one for you except for in certain circumstances (fully listed in the link above in the Deleted implicitly-declared default constructor section)
T has a member of reference type without a default initializer.
T has a const member without user-defined default constructor or a default member initializer (since C++11).
T has a member (without a default member initializer) (since C++11) which has a deleted default constructor, or its default constructor is ambiguous or inaccessible from this constructor.
T has a direct or virtual base which has a deleted default constructor, or it is ambiguous or inaccessible from this constructor.
T has a direct or virtual base which has a deleted destructor, or a destructor that is inaccessible from this constructor.
T is a non-union class with a variant member M with a non-trivial default constructor, and no variant member of the anonymous union containing M has a default member initializer.
and some additional rules for union types.
tl;dr: it's complicated.
Implicit default constructors are not created for all objects.
The main rule is that when an object has no constructors of any kind, it gets assign an implicit default constructor.
I won't go over all the specific rules dictating when they get created, you're better off reading them from here.
As for your question 1 on the error message:
I tried to declare the object author inside the constructor instead of initializer list. It gave me error.
You don't show the code that produced the error, so I will assume it is like below - correct me if I'm wrong.
// sample A - Bad code, wont compile
class Author { };
class Book
{
public:
Book(int x, Author y): n(1) {
a(y); //-this line does NOT compile.
// initialization of a must be in the initializer list,
// between : and {
}
private:
Author a;
int n;
};
The reason the above does not compile is because it is a language rule that nested objects declared by value must be initialized in one of these 2 ways:
- within the initializer list
- implicitly, by letting the compiler call the default constructor - which will work if the object has one.
Finally, on your question 2, yes, that sample declaration of Point does invoke the default constructor, if the class has one. Again, refer to language reference to clarify on when the default constructor exists or not.
I apologize in advance because some of my verbiage may not be 100% correct.
I will have a class like this:
class ClassName {
private:
AnotherClass class2;
public:
ClassName();
~ClassName();
...
In the constructor of this class, among other things, I put the line
ClassName::ClassName() {
AnotherClass class2;
}
Which is how I thought you were supposed to initialize objects in C++, however I was noticing (through GDB) that two AnotherClass objects were being created. Once on the Constructor definition then again on my initialization line. What is the reasoning behind this? What if I wanted to use a more complicated constructor like AnotherClass(int a, int b), would it create a temporary object then create the correct one shortly after?
AnotherClass class2; creates another local object inside the constructor body, that gets destroyed at the end of the body. That is not how class members are initialized.
Class members are initialized before the constructor body in the member initializer list between the constructor signature and body, starting with a :, like so:
ClassName::ClassName() :
class2(argumentsToPassToClass2Constructor),
anotherMember(42) // just for example
{
/* constructor body, usually empty */
}
If you don't want to pass any arguments to the class2 constructor you don't have to put it in the initializer list. Then its default constructor will be called.
If you simply want to call the default constructor on all of your class members, you can (and should) omit the constructor altogether. The implicitly generated default constructor will do just what you wanted.
What you are doing in your constructor is creating another variable, local only inside the constructor.
Actually, if you do nothing, the default constructor in AnotherClass will be called for the class2 object.
If you want to be explicit, you can use a constructor initializer list:
ClassName::ClassName()
: class2()
{
}
This last method is also the way you call a specific constructor with arguments in AnotherClass, if you need to do that.
ClassName::ClassName() {
AnotherClass class2; // this will create local variable only
}
If AnotherClass will have default constructor, then it will be called for the class2 object by compiler.
If you want to call parametrized constructor then you will have do it in following way:
ClassName::ClassName() :
class2(arguments)
Why to use and How to use initializer list :
Consider the following example:
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
Here compiler follows following steps to create an object of type MyClass
Type’s constructor is called first for “a”.
The assignment operator of “Type” is called inside body of MyClass() constructor to assign
variable = a;
And then finally destructor of “Type” is called for “a” since it goes out of scope.
Now consider the same code with MyClass() constructor with Initializer List
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
With the Initializer List, following steps are followed by compiler:
Copy constructor of “Type” class is called to initialize : variable(a). The arguments in initializer list are used to copy construct “variable” directly.
Destructor of “Type” is called for “a” since it goes out of scope.
As we can see from this example if we use assignment inside constructor body there are three function calls: constructor + destructor + one addition assignment operator call. And if we use Initializer List there are only two function calls: copy constructor + destructor call.
This assignment penalty will be much more in “real” applications where there will be many such variables.
Few more scenarios, where you will have to use initializer list only:
Parametrized constructor of base class can only be called using Initializer List.
For initialization of reference members
For initialization of non-static const data members
You are just creating a local variable in this line. In general there are three ways of initializing private members:
Default initialization
If you do nothing on your constructor, the compiler will automatically initialize the private member by calling its default constructor (ctr without parameters)
Assigning them to a value in the ctr body
In this case you have to assign the desired value to your private member by using the assignment operator.
ClassName::ClassName()
{
class2 = AnotherClass(a, b, c); // if the class ctr has some parameters
}
By using the initialization list
In your case it will be something like:
ClassName::ClassName()
: class2(initial_value)
{
}
This is in general the best and efficient option for initializing your class private members since you avoid calling the copy constructor for the passed parameters. This is in general is not an issue unless the copy ctr contains time-consuming operations. The same apply for the option #2 in this case you may have the same issues with the assignment operator
What you did there is to create a new variable with the same name as you member,
By doing this you overshadowed your member variable.
Also, in the process your member constructor was silently called in the ClassName empty initialisation list.
you can initiate the class in two ways:
ClassName::ClassName(): class2() {}
or:
ClassName::ClassName() {
this->class2 = AnotherClass();
}
The first way is better and a must some times.
If you only use empty constructors for your members you won't see the difference, except in performance, because the compiler initialize the member by default in its initialisation list ( the part after the ":", if you don't do that, he does it silently for you... )
But if your member doesn't have an empty constructor, for example:
AnotherClass:: AnotherClass(int a, int b)
if you will try to use the second way on initialisation you will get a message like:
error: constructor for 'Initiator' must explicitly initialize the member 'class2' which does not have a default constructor
I am writing the following classes in C++.
class SImage {
...
public:
SImage(char*);
}
class SImageProc {
SImage S;
...
public:
SImageProc(SImage Im) { S = Im; };
}
When compiling I receive this referencing the line where I implement my constructor:
SImageProc.cpp:5:33: error: no matching function for call to 'SImage::SImage()'
I cannot figure out why it is interpreting my parameters as instantions of a class when implementing the SImageProc class.
SImage does not have a default constructor, because you have provided constructor SImage(char*). This means the compiler no longer provides a default one. Something elsewhere in your code requires SImage, causing the error.
You need to provide a default constructor for SImage, or remove the code that requires it. It is not possible to say which one of the solutions is suitable without more details.
My wild guess would be that SImageProc has an SImage data member, and you are not initializing it in the constructor initialization list. This is how you would fix that problem:
SImageProc(SImage Im) : S(Im) {};
The explanation for that is that, by the time you reach a constructor's body, all data members and bases have been initialized. After initialization you can only modify them (in your example, you were assigning to S.) If you do not explicitly initialize data members and bases in the constructor initialization list, they (usually) get default initialized, which in the case of a user defined type means the default constructor is called. This is the source of the error.
If the class doesn't have the constructor, will the compiler make one default constructor for it ?
Programmers new to C++ often have two common misunderstandings:
That a default constructor is synthesized for every class that does
not define one
from the book Inside the C++ Object Model
I am at a loss...
This is well explained in the section from which this quote is taken. I will not paraphrase it in its entirety, but here is a short summary of the section content.
First of all, you need to understand the following terms: implicitly-declared, implicitly-defined, trivial, non-trivial and synthesized (a term that is used by Stanley Lippman, but is not used in the standard).
implicitly-declared
A constructor is implicitly-declared for a class if there is no user-declared constructor in this class. For example, this class struct T { }; does not declare any constructor, so the compiler implicitly declares a default constructor. On the other hand, this class struct T { T(int); }; declares a constructor, so the compiler will not declare an implicit default constructor. You will not be able to create an instance of T without parameters, unless you define your own default constructor.
implicitly-defined
An implicitly-declared constructor is implicitly-defined when it is used, i.e. when an instance is created without parameters. Assuming the following class struct T { };, the line T t; will trigger the definition of T::T(). Otherwise, you would have a linker error since the constructor would be declared but not defined. However, an implicitly-defined constructor does not necessarily have any code associated with it! A default constructor is synthesized (meaning that some code is created for it) by the compiler only under certain circumstances.
trivial constructor
An implicitly-declared default constructor is trivial when:
its class has no virtual functions and no virtual base classes and
its base classes have trivial constructors and
all its non-static members have trivial constructors.
In this case, the default compiler has nothing to do, so there is no code synthesized for it. For instance, in the following code
struct Trivial
{
int i;
char * pc;
};
int main()
{
Trivial t;
}
the construction of t does not involve any operations (you can see that by looking at the generated assembly: no constructor is called to construct t).
non-trivial
On the other hand, if the class does not meet the three requirements stated above, its implicitly-declared default constructor will be non-trivial, meaning that it will involve some operations that must be performed in order to respect the language semantics. In this case, the compiler will synthesize an implementation of the constructor performing these operations.
For instance, consider the following class:
struct NonTrivial
{
virtual void foo();
};
Since it has a virtual member function, its default constructor must set the virtual table pointer to the correct value (assuming the implementation use a virtual method table, of course).
Similarly, the constructor of this class
struct NonTrivial
{
std::string s;
};
must call the string default constructor, as it is not trivial. To perform these operations, the compiler generates the code for the default constructor, and calls it anytime you create an instance without parameters. You can check this by looking at the assembly corresponding to this instantiation NonTrivial n; (you should see a function call, unless the constructor has been inlined).
Summary
When you don't provide any constructor for your class, the compiler implicitly declares a default one. If you try to use it, the compiler implicitly defines it, if it can (it is not always possible, for instance when a class has a non-default-constructible member). However, this implicit definition does not imply the generation of any code. The compiler needs to generate code for the constructor (synthesize it) only if it is non-trivial, meaning that it involves certain operations needed to implement the language semantics.
N.B.
Stanley B Lippman's "Inside the C++ object model" and this answer deals with (a possible) implementation of C++, not its semantics. As a consequence, none of the above can be generalized to all compilers: as far as I know, an implementation is perfectly allowed to generate code even for a trivial constructor. From the C++ user point of view, all that matters is the "implicitly-declared/defined` aspect (and also the trivial/non-trivial distinction, as it has some implications (for instance, an object of a class with non-trivial constructor cannot be a member of a union)).
I think the misconception is:
That a default constructor is synthesized for every class that does not define one
That people think the default constructor, which accepts no arguments, will always be generated if you don't declare it yourself.
However, this is not true, because if you declare any constructor yourself, the default one will not be automatically created.
class MyClass {
public:
MyClass(int x) {}; // No default constructor will be generated now
};
This will lead to problems like when beginners expect to use MyClass like this:
MyClass mc;
Which won't work because there is no default constructor that accepts no args.
edit as OP is still a little confused.
Imagine that my MyClass above was this:
class MyClass {
};
int main() {
MyClass m;
}
That would compile, because the compiler will autogenerate the default constructor MyClass() because MyClass was used.
Now take a look at this:
#include <iostream>
class MyClass {
};
int main() {
std::cout << "exiting\n";
}
If this were the only code around, the compiler wouldn't even bother generating the default constructor, because MyClass is never used.
Now this:
#include <iostream>
class MyClass {
public:
MyClass(int x = 5) { _x = x; }
int _x;
};
int main() {
MyClass m;
std::cout << m._x;
}
The compiler doesn't generate default constructor MyClass(), because the class already has a constructor defined by me. This will work, and MyClass(int x = 5) works as your default constructor because it can accept no arguments, but it wasn't generated by the compiler.
And finally, where beginners might run into a problem:
class MyClass() {
public:
MyClass(int x) { _x = x; }
int _x;
};
int main() {
MyClass m;
}
The above will throw you an error during compilation, because MyClass m needs a default constructor (no arguments) to work, but you already declared a constructor that takes an int. The compiler will not generate a no-argument constructor in this situation either.
A default constructor is synthesized for every class that does not define one if:
The code using the class needs one & only if
There is no other constructor explicitly defined for the class by you.
All the upvoted answers thus far seem to say approximately the same thing:
A default constructor is synthesized for every class that does not have any user-defined constructor.
which is a modification of the statement in the question, which means
A default constructor is synthesized for every class that does not have a user-defined default constructor.
The difference is important, but the statement is still wrong.
A correct statement would be:
A default constructor is synthesized for every class that does not have any user-defined constructor and for which all sub-objects are default-constructible in the context of the class.
Here are some clear counter-examples to the first statement:
struct NoDefaultConstructor
{
NoDefaultConstructor(int);
};
class Surprise1
{
NoDefaultConstructor m;
} s1; // fails, no default constructor exists for Surprise1
class Surprise1 has no user-defined constructors, but no default constructor is synthesized.
It doesn't matter whether the subobject is a member or a base:
class Surprise2 : public NoDefaultConstructor
{
} s2; // fails, no default constructor exists for Surprise2
Even if all subobjects are default-constructible, the default constructor has to be accessible from the composite class:
class NonPublicConstructor
{
protected:
NonPublicConstructor();
};
class Surprise3
{
NonPublicConstructor m;
} s3; // fails, no default constructor exists for Surprise3
Yes a default constructor is always there by default if you don't define a constructor of your own (see the default constructor section here).
http://www.codeguru.com/forum/archive/index.php/t-257648.html
Quote:
The following sentense are got from the book "Inside the C++ object model" , written by Stanley B. Lippman.
There are four characteristics of a class under which the compiler
needs to synthesize a default constructor for classes that declare no
constructor at all. The Standard refers to these as implicit,
nontrivial default constructors. The synthesized constructor fulfills
only an implementation need. It does this by invoking member object or
base class default constructors or initializing the virtual function
or virtual base class mechanism for each object. Classes that do not
exhibit these characteristics and that declare no constructor at all
are said to have implicit, trivial default constructors. In practice,
these trivial default constructors are not synthesized. ...
Programmers new to C++ often have two common misunderstandings:
That a default constructor is synthesized for every class that does
not define one
That the compiler-synthesized default constructor provides explicit
default initializers for each data member declared within the class
As you have seen, neither of these is true.