As C++11 introduces the new uniform initialization syntax, many recommend to use it instead the old style syntax.
At least, if it weren't for this so-called corner case:
struct Foo {
Foo(int){
std::cout << "default" << std::endl;
}
Foo(std::initializer_list<int>){
std::cout << "initlist" << std::endl;
}
};
int main(){
Foo f{200}; //prints "initlist"
}
Using a {}-always-style screams for trouble, especially in templates. There seem to be only three safe usages for the new syntax:
explicitly requesting std::initializer_list-constructors
POD-constructors
default-constructors
But there's also a case in which we have to use uniform initialization syntax: non-static data member initializers.
For some reason, C++ can recognize
void Bar() {
Foo f(200);
}
but can't deal with
struct Bar {
Foo f(200);
};
Question #1: Why does the ()-syntax work inside a function but not a class? Does anyone know the rationale behind this?
Putting it all together, lastly we arrive at this silly case:
struct FooBar {
std::vector<int> bar(50); //doesn't work
std::vector<int> bar{50}; //not the intended effect
std::vector<int> bar = std::vector<int>(50); //works
};
Of course, you also can't use auto for data members.
So I either have to awkwardly mix all syntaxes or not use these features at all.
Question #2: Did I misunderstand something? This can't be intended behavior, can it?
Question #1: Why does the ()-syntax work inside a function but not a class? Does anyone know the rationale behind this?
Because it can look like a function declaration, and there already is enough confusion regarding that:
Foo f(); // function declaration. This still catches people out
But you can use (), just using the copy-initialization syntax:
T t = T(args);
Question #2: Did I misunderstand something? This can't be intended behavior, can it?
It is the design behaviour. It is unfortunate that it doesn't play very well with standard library containers of certain types (like std::vector<int> in your example). You just have to remember that an implicit initializer_list constructor trumps all other compatible constructors. You should strive to design your own classes such that they don't suffer from this problem.
See this related question: When to use a brace-enclosed initializer?
It's not allowed because it would lead to more instances of the "most vexing parse" which is already annoying. This isn't a major handicap because you can still use initialization syntax in the constructor body, or use the copy-initialization form.
If you bear in mind that the semantics of a brace-enclosed list is and has always been to provide a list of values to store in the object, then it's clear that std::vector<int> bar{50} should (and does) create a vector containing one int.
Related
I realized that in C++ you can initialize any structure with default values. I don't think that was possible under C. Is that correct?
Are there situations in which it still makes sense not to use such a default initialization? Or is it better in any case since it is safer?
I also saw that there are different ways to do this.
Is One Method Better Than Another? Or is it just a matter of taste?
struct STR_Foo {
int value{ 0 };
};
struct STR_Foo {
int value = 0;
};
struct STR_Foo {
int value = { 0 };
};
I realized that in C++ you can initialize any structure with default values. I don't think that was possible under C. Is that correct?
Yes.
Are there situations in which it still makes sense not to use such a default initialization?
If you target Older standard than C++11 - or cross-compatibility with C. Default member initialisers weren't in the language before that - and aren't in C.
If you target C++11 standard and you want the class to be an aggregate. Since C++14 default member initialisers don't disqualify a class from being an aggregate.
If you need an instance of the class to be initialised later and have measured that you cannot afford the very low overhead of redundant initialisation.
I also saw that there are different ways to do this. Is One Method Better Than Another? Or is it just a matter of taste?
The choice to use = or not is stylistic when using curly brackets. Attempting to initialise without = and parentheses instead of curlies ends up being a function declaration for some cases, so you need to disambiguate by using = or curlies.
Curly brackets affect the form of initialisation in some cases. In cases where curlies and no curlies invoke the same constructor, using curlies is recommended because that syntax don't allow narrowing conversions. When curlies invoke a different constructor than no curlies, use the form that does what you need.
These apply to all initialisation; not just default members.
In C++ the following code gives a compiler error:
void destruct1 (int * item)
{
item->~int();
}
This code is nearly the same, I just typedef the int to another type and something magic happens:
typedef int myint;
void destruct2 (myint * item)
{
item->~myint();
}
Why does the second code work? Does an int get a destructor just because it has been typedefed?
In case you wonder why one ever would like to do this: This comes from refactoring C++ code. We're removing the standard heap and replacing it with selfmade pools. This requires us to call placement-new and the destructors. I know that calling destructors for primitive types is useless, but we want them in the code nevertheless in case we later replace PODs with real classes.
Finding out that naked int's don't work but typedefed ones do was quite a surprise.
Btw - I have a solution that involves template-functions. We just typedef inside the template and everything is fine.
It's the reason that makes your code work for generic parameters. Consider a container C:
template<typename T>
struct C {
// ...
~C() {
for(size_t i = 0; i<elements; i++)
buffer[i].~T();
}
};
It would be annoying to introduce special cases for built-in types. So C++ allows you to do the above, even if T happens to equal to int. The holy Standard says in 12.4 p15:
The notation for explicit call of a destructor can be used for any scalar type name. Allowing this makes it possible to write code without having to know if a destructor exists for a given type.
The difference between using a plain int and a typedef'ed int is that they are syntactically different things. The rule is, that in a destructor call, the thing after the ~ is a type-name. int is not such a thing, but a typedef-name is. Look it up in 7.1.5.2.
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).
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.