C++11 introduced this:
struct MyClass {
int foo = 0; //*
};
Until now I've been using this without thinking about it, but now I'm wondering:
Is this initialization doing/executing any actual initialization at this particular line (//* in the code), or is this a mere convenience notation that only does/executes something later, when the object is actually constructed?
Not sure what you mean by "later" and "at this particular line", but the above is equivalent to the following:
struct MyClass {
MyClass() : foo(0) { }
};
So if I understand your question correctly, then the answer is: "Yes, only when the object is actually constructed".
Declarations are not executable code, they do not execute anything. This is merely a convenient notation for inserting initialization of foo to zero into every constructor that you define (or into an implicitly defined default constructor, if you do not define any constructors yourself).
Related
Triggered by this answer I was reading in the core guidelines:
C.45: Don’t define a default constructor that only initializes data
members; use in-class member initializers instead
The reasoning given is
Reason
Using in-class member initializers lets the compiler generate the
function for you. The compiler-generated function can be more
efficient.
Note that this is specifically about a default constructor that does nothing but initialize the members and the guideline suggests that one should not write such a constructor.
The "bad" example is:
Example, bad
class X1 { // BAD: doesn't use member initializers
string s;
int i;
public:
X1() :s{"default"}, i{1} { }
// ...
};
The "good" example is using in-class member initializers and no user declared constructor:
Example
class X2 {
string s = "default";
int i = 1;
public:
// use compiler-generated default constructor
// ...
};
What can the compiler generated constructor do more efficient than the user-provided one in that particular example (or in any other example)?
Is the initializer list not giving the same opportunities for optimization as in-class initializers?
Short Answer
A defaulted constructor should have the same generated assembly as the equivalent initializer constructor provided that the author includes the correct constexpr and noexcept statuses.
I suspect the "can be more efficient" is referring to the fact that, in general, it will generate more optimal code than the equivalent developer-authored one that misses opportunities such as inline, constexpr, and noexcept.
Long Answer
An important feature that defaulted constructors perform is that they interpret and deduce the correct status for both constexpr and noexcept
This is something that many C++ developers do not specify, or may not specify correctly. Since Core Guidelines targets both new and old C++ developers, this is likely why the "optimization" is being mentioned.
The constexpr and noexcept statuses may affect code generation in different ways:
constexpr constructors ensure that invocations of a constructor from values yielded from constant expressions will also yield a constant expression. This can allow things like static values that are not constant to not actually require a constructor invocation (e.g. no static initialize overhead or locking required). Note: this works for types that are not, themselves, able to exist in a constexpr context -- as long as the constexprness of the constructor is well-formed.
noexcept may generate better assembly of consuming code since the compiler may assume that no exceptions may occur (and thus no stack-unwinding code is necessary). Additionally, utilities such as templates that check for std::is_nothrow_constructible... may generate more optimal code paths.
Outside of that, defaulted constructors defined in the class-body also make their definitions visible to the caller -- which allows for better inlining (which, again, may otherwise be a missed-opportunity for an optimization).
The examples in the Core Guidelines don't demonstrate these optimizations very well. However, consider the following example, which illustrates a realistic example that can benefit from defaulting:
class Foo {
int a;
std::unique_ptr<int> b;
public:
Foo() : a{42}, b{nullptr}{}
};
In this example, the following are true:
A construction of Foo{} is not a constant expression
Construction of Foo{} is not noexcept
Contrast this to:
class Foo {
int a = 42;
std::unique_ptr<int> b = nullptr;
public:
Foo() = default;
};
On the surface, this appears to be the same. But suddenly, the following now changes:
Foo{} is constexpr, because std::unique_ptr's std::nullptr_t constructor is constexpr (even though std::unique_ptr cannot be used in a full constant expression)
Foo{} is a noexcept expression
You can compare the generated assembly with this Live Example. Note that the default case does not require any instructions to initialize foo; instead it simply assigns the values as constants through compiler directive (even though the value is not constant).
Of course, this could also be written:
class Foo {
int a;
std::unique_ptr<int> b;
public:
constexpr Foo() noexcept :a{42}, b{nullptr};
};
However, this requires prior knowledge that Foo is able to be both constexpr and noexcept. Getting this wrong can lead to problems. Worse yet, as code evolves over time, the constexpr/noexcept state may become incorrect -- and this is something that defaulting the constructor would have caught.
Using default also has the added benefit that, as code evolves, it may add constexpr/noexcept where it becomes possible -- such as when the standard library adds more constexpr support. This last point is something that would otherwise be a manual process every time code changes for the author.
Triviality
If you take away the use of in-class member initializers, then there is one last worthwhile point mentioning: there is no way in code to achieve triviality unless it gets compiler-generated (such as through defaulted constructors).
class Bar {
int a;
public:
Bar() = default; // Bar{} is trivial!
};
Triviality offers a whole different direction on potential optimizations, since a trivial default-constructor requires no action on the compiler. This allows the compiler to omit any Bar{} entirely if it sees that the object is later overwritten.
I think that it's important to assume that C.45 refers to constants (example and enforcement):
Example, bad
class X1 { // BAD: doesn't use member initializers
string s;
int i; public:
X1() :s{"default"}, i{1} { }
// ... };
Example
class X2 {
string s = "default";
int i = 1; public:
// use compiler-generated default constructor
// ... };
Enforcement
(Simple) A default constructor should do more than just initialize
member variables with constants.
With that in mind, it's easier to justify (via C.48) why we should prefer in-class initializers to member initializers in constructors for constants:
C.48: Prefer in-class initializers to member initializers in
constructors for constant initializers
Reason
Makes it explicit that the same value is expected to be used in all
constructors. Avoids repetition. Avoids maintenance problems. It leads
to the shortest and most efficient code.
Example, bad
class X { // BAD
int i; string s;
int j; public:
X() :i{666}, s{"qqq"} { } // j is uninitialized
X(int ii) :i{ii} {} // s is "" and j is uninitialized
// ... };
How would a maintainer know whether j was deliberately uninitialized
(probably a poor idea anyway) and whether it was intentional to give s
the default value "" in one case and qqq in another (almost certainly
a bug)? The problem with j (forgetting to initialize a member) often
happens when a new member is added to an existing class.
Example
class X2 {
int i {666};
string s {"qqq"};
int j {0}; public:
X2() = default; // all members are initialized to their defaults
X2(int ii) :i{ii} {} // s and j initialized to their defaults
// ... };
Alternative: We can get part of the benefits from default arguments to
constructors, and that is not uncommon in older code. However, that is
less explicit, causes more arguments to be passed, and is repetitive
when there is more than one constructor:
class X3 { // BAD: inexplicit, argument passing overhead
int i;
string s;
int j; public:
X3(int ii = 666, const string& ss = "qqq", int jj = 0)
:i{ii}, s{ss}, j{jj} { } // all members are initialized to their defaults
// ... };
Enforcement
(Simple) Every constructor should initialize every member variable (either explicitly, via a delegating ctor call or via default
construction).
(Simple) Default arguments to constructors suggest an in-class initializer may be more appropriate.
Rather surprised to find this question not asked before. Actually, it has been asked before but the questions are VERY DIFFERENT to mine. They are too complicated and absurd while I'll keep it simple and to the point. That is why this question warrants to be posted.
Now, when I do this,
struct A {
int a = -1;
};
I get the following error:
ANSI C++ forbids in-class initialization of non-const static member a
Now, along with the workaround can someone please tell me THE BEST way of initializing a struct member variable with a default value?
First, let's look at the error:
ANSI C++ forbids in-class initialization of non-const static member a
Initialization of a true instance member, which resides within the memory of an instance of your struct is the responsibility of this struct's constructor.
A static member, though defined inside the definition of a particular class/struct type, does not actually reside as a member of any instances of this particular type. Hence, it's not subject to explaining which value to assign it in a constructor body. It makes sense, we don't need any instances of this type for the static member to be well-initialized.
Normally, people write member initialization in the constructor like this:
struct SomeType
{
int i;
SomeType()
{
i = 1;
}
}
But this is actually not initialization, but assignment. By the time you enter the body of the constructor, what you've done is default-initialize members. In the case of a fundamental type like an int, "default-initialization" basically boils down to "eh, just use whatever value was in those bytes I gave you."
What happens next is that you ask i to now adopt the value 1 via the assignment operator. For a trivial class like this, the difference is imperceptible. But when you have const members (which obviously cannot be tramped over with a new value by the time they are built), and more complex members which cannot be default-initialized (because they don't make available a visible constructor with zero parameters), you'll soon discover you cannot get the code to compile.
The correct way is:
struct SomeType
{
int i;
SomeType() : i(1)
{
}
}
This way you get members to be initialized rather than assigned to. You can initialize more than one by comma-separating them. One word of caution, they're initialized in the order of declaration inside your struct, not how you order them in this expression.
Sometimes you may see members initialized with braces (something like i{1} rather i(c)). The differences can be subtle, most of the time it's the same, and current revisions of the Standard are trying to smooth out some wrinkles. But that is all outside the scope of this question.
Update:
Bear in mind that what you're attempting to write is now valid C++ code, and has been since ratification of C++11. The feature is called "Non-static data member initializers", and I suspect you're using some version of Visual Studio, which still lists support as "Partial" for this particular feature. Think of it as a short-hand form of the member initialization syntax I described before, automatically inserted in any constructor you declare for this particular type.
You could make a default constructor
struct A {
A() : a{-1} {}
int a;
};
Sorry if title is confusing, I couldn't find an easy way to write it in a simple sentence. Anyways, the issue I'm facing:
// header:
class SomeThing
{
private:
SomeThing() {} // <- so users of this class can't come up
// with non-initialized instances, but
// but the implementation can.
int some_data; // <- a few bytes of memory, the default
// constructor SomeThing() doesn't initialize it
public:
SomeThing(blablabla ctor arguments);
static SomeThing getThatThing(blablabla arguments);
static void generateLookupTables();
private:
// declarations of lookup tables
static std::array<SomeThing, 64> lookup_table_0;
static SomeThing lookup_table_1[64];
};
The getThatThing function is meant to return an instance from a lookup table.
// in the implementation file - definitions of lookup tables
std::array<SomeThing, 64> SomeThing::lookup_table_0; // error
SomeThing Something::lookup_table_1[64]; // <- works fine
I just can't use a std::array of Something, unless I add a public ctor SomeThing() in the class. It works fine with old-style arrays, I can define the array, and fill it up in the SomeThing::generateLookupTables() function. Apparently the type std::array<SomeThing, 64> does not have a constructor. Any ideas on how to make it work, or maybe a better structure for this concept?
============= EDIT =======
The friend std::array<SomeThing, 64> approach seems like a nice idea, but:
It is going to be used in arrays in other places as well. I would like to guarantee this class to always keep certain invariants towards to external users. With this friendly array, a user can accidentally create an uninitialised array of SomeThing.
Also, the lookup tables are generated using a rather complicated process, can't be done per inline, as in std::array<SomeThing, 64> SomeThing::lookup_table_0(some value)
The std::array<SomeThing, 64> class clearly doesn't have access to the private default constructor when it tries to define the instance. You can give it the necessary access by adding
friend class std::array<SomeThing, 64>;
to the definition of SomeThing.
The solution:
std::array<SomeThing, 64> SomeThing::lookup_table_0 {{ }};
Note: as explained here, {{}} is required to value-initialize the std::array without warnings in gcc. = {} and {} are correct but gcc warns anyway.
The key to the solution is that some form of initializer must be present.
A terminology check first: all objects are initialized in C++. There are three forms of this, default, value and zero. There are no "non-initialized" objects ; objects with no explicit initializer are called default-initialized. In some circumstances this means the member variables of the object may be indeterminate ("garbage").
What is the problem with the no-initializer version? Firstly, the constructor for std::array<SomeThing, 64> is defined as deleted because the declaration std::array<SomeThing, 64> x; would be ill-formed (due to lack of an accessible default constructor for SomeThing, of course).
That means that any code which attempts to use the default constructor for std::array<SomeThing, 64> is in turn ill-formed. The definition:
std::array<SomeThing, 64> SomeThing::lookup_table_0;
does attempt to use the default constructor, so it is ill-formed. However once you start introducing initializers, then the default constructor for std::array is no longer in play; since std::array is an aggregate then aggregate initialization occurs which bypasses the implicitly-generated constructor(s). (If there were any user-declared constructors then it would no longer be an aggregate).
The version with initializers works because of [dcl.init]/13 (n3936):
An initializer for a static member is in the scope of the member’s class
The definition of list-initialization transforms { } to { SomeThing() } here.
As your constructor is private, std::array can't use it.
You may add friend class std::array<SomeThing, 64>; in SomeThing to give access to the constructor.
An alternative is to use the available public constructor to initialize the element of array:
std::array<SomeThing, 64> SomeThing::lookup_table_0{
SomeThing(blablabla_ctor_arguments), ..
};
EDIT:
You can even do, if you have your move or copy constructor available:
std::array<SomeThing, 64> SomeThing::lookup_table_0{ SomeThing() };
to have your whole array default initialized.
This may be a silly question, but still I'm a bit curious...
Recently I was working on one of my former colleague projects, and I've noticed that he really loved to use something like this:
int foo(7);
instead of:
int foo = 7;
Is this a normal/good way to do in C++ language?
Is there some kind of benefits to it? (Or is this just some silly programming style that he was into..?)
This really reminds me a bit of a good way how class member variables can be assigned in the class constructor... something like this:
class MyClass
{
public:
MyClass(int foo) : mFoo(foo)
{ }
private:
int mFoo;
};
instead of this:
class MyClass
{
public:
MyClass(int foo)
{
mFoo = foo;
}
private:
int mFoo;
};
For basic types there's no difference. Use whichever is consistent with the existing code and looks more natural to you.
Otherwise,
A a(x);
performs direct initialization, and
A a = x;
performs copy initialization.
The second part is a member initializer list, there's a bunch of Q&As about it on StackOverflow.
Both are valid. For builtin types they do the same thing; for class types there is a subtle difference.
MyClass m(7); // uses MyClass(int)
MyClass n = 3; // uses MyClass(int) to create a temporary object,
// then uses MyClass(const MyClass&) to copy the
// temporary object into n
The obvious implication is that if MyClass has no copy constructor, or it has one but it isn't accessible, the attempted construction fails. If the construction would succeed, the compiler is allowed to skip the copy constructor and use MyClass(int) directly.
All the answers above are correct. Just add that to it that C++11 supports another way, a generic one as they say to initialize variables.
int a = {2} ;
or
int a {2} ;
Several other good answers point out the difference between constructing "in place" (ClassType v(<constructor args>)) and creating a temporary object and using the copy constructor to copy it (ClassType v = <constructor arg>). Two additional points need to be made, I think. First, the second form obviously has only a single argument, so if your constructor takes more than one argument, you should prefer the first form (yes, there are ways around that, but I think the direct construction is more concise and readable - but, as has been pointed out, that's a personal preferance).
Secondly, the form you use matters if your copy constructor does something significantly different than your standard constructor. This won't be the case most of the time, and some will argue that it's a bad idea to do so, but the language does allow for this to be the case (all surprises you end up dealing with because of it, though, are your own fault).
It's a C++ style of initializing variables - C++ added it for fundamental types so the same form could be used for fundamental and user-defined types. this can be very important for template code that's intended to be instantiated for either kind of type.
Whether you like to use it for normal initialization of fundamental types is a style preference.
Note that C++11 also adds the uniform initialization syntax which allows the same style of initialization to be used for all types - even aggregates like POD structs and arrays (though user defined types may need to have a new type of constructor that takes an initialization list to allow the uniform syntax to be used with them).
Yours is not a silly question at all as things are not as simple as they may seem. Suppose you have:
class A {
public:
A() {}
};
and
class B {
public:
class B(A const &) {}
};
Writing
B b = B(A());
Requires that B's copy constructor be accessible. Writing
B b = A();
Requires also that B's converting constructor B(A const &) be not declared explicit. On the other hand if you write
A a;
B b(a);
all is well, but if you write
B b(A());
This is interpreted by the compiler as the declaration of a function b that takes a nameless argument which is a parameterless function returning A, resulting in mysterious bugs. This is known as C++'s most vexing parse.
I prefer using the parenthetical style...though I always use a space to distinguish from function or method calls, on which I don't use a space:
int foo (7); // initialization
myVector.push_back(7); // method call
One of my reasons for preferring using this across the board for initialization is because it helps remind people that it is not an assignment. Hence overloads to the assignment operator will not apply:
#include <iostream>
class Bar {
private:
int value;
public:
Bar (int value) : value (value) {
std::cout << "code path A" << "\n";
}
Bar& operator=(int right) {
value = right;
std::cout << "code path B" << "\n";
return *this;
}
};
int main() {
Bar b = 7;
b = 7;
return 0;
}
The output is:
code path A
code path B
It feels like the presence of the equals sign obscures the difference. Even if it's "common knowledge" I like to make initialization look notably different than assignment, since we are able to do so.
It's just the syntax for initialization of something :-
SomeClass data(12, 134);
That looks reasonable, but
int data(123);
Looks strange but they are the same syntax.
Observation: the codes pasted below were tested only with GCC 4.4.1, and I'm only interested in them working with GCC.
Hello,
It wasn't for just a few times that I stumbled into an object construction statement that I didn't understand, and it was only today that I noticed what ambiguity was being introduced by it. I'll explain how to reproduce it and would like to know if there's a way to fix it (C++0x allowed). Here it goes.
Suppose there is a class whose constructor takes only one argument, and this one argument's type is another class with a default constructor. E.g.:
struct ArgType {};
class Class
{
public:
Class(ArgType arg);
};
If I try to construct an object of type Class on the stack, I get an ambiguity:
Class c(ArgType()); // is this an object construction or a forward declaration
// of a function "c" returning `Class` and taking a pointer
// to a function returning `ArgType` and taking no arguments
// as argument? (oh yeh, loli haets awkward syntax in teh
// saucecode)
I say it's an object construction, but the compiler insists it's a forward declaration inside the function body. For you who still doesn't get it, here is a fully working example:
#include <iostream>
struct ArgType {};
struct Class {};
ArgType func()
{
std::cout << "func()\n";
return ArgType();
}
int main()
{
Class c(ArgType());
c(func); // prints "func()\n"
}
Class c(ArgType funcPtr()) // Class c(ArgType (*funcPtr)()) also works
{
funcPtr();
return Class();
}
So well, enough examples. Anyone can help me get around this without making anything too anti-idiomatic (I'm a library developer, and people like idiomatic libraries)?
-- edit
Never mind. This is a dupe of Most vexing parse: why doesn't A a(()); work?.
Thanks, sbi.
This is known as "C++'s most vexing parse". See here and here.
Let's simplify a little.
int f1();
What's that? The compiler (and I) say it's a forward declaration for a function returning an integer.
How about this?
int f2(double );
The compiler (and I) say it's a forward declaration for a function taking a double argument and returning an int.
So have you tried this:
ClassType c = ClassType(ArgType());
Check out the c++ faq lite on constructors for explanations and examples
Based on the "C++0x allowed", the right answer is (probably) to change the definition to:
Class c(ArgType {});
Simple, straightforward and puts the burden entirely on the user of the library, not the author!
Edit: Yes, the ctor is invoked -- C++ 0x adds List-Initialization as an unambiguous way to delimit initializer lists. It can't be mis-parsed like in your sample, but otherwise the meaning is roughly the same as if you used parentheses. See N3000, the third bullet point under §8.5.4/3. You can write a ctor to receive an initializer list as a single argument, or the items in the initializer list can be matched up with the ctor arguments individually.