I did a test here, but the output is a loop without ending, I don't know why.
Actually, I am doing another test, but when I wrote this, I don't understand how the loop occurred. It is output "ABC" repeatedly.
#include <map>
#include <string>
#include <iostream>
class test
{
public:
std::map <int, int> _b;
test();
test (std::map<int, int> & im);
~test();
};
test::test()
{
std::cout<<"abc";
_b.clear();
_b[1]=1;
test(_b);
}
test::test(std::map <int, int>& im)
{
std::cout<<im[1];
}
test::~test() {};
int main ()
{
test a;
}
The issue here is that the compiler interprets the statement
test(_b);
not as code that creates a temporary object of type test passing in parameter _b, but as a variable declaration for a variable named _b of type test, using the default constructor. Consequently, what looks like a piece of code that creates a temporary test object using the second constructor is instead recursively creating a new object of type test and invoking the constructor another time.
To fix this, you can give the variable an explicit name, such as
test t(_b);
This can only be interpreted as a variable of type test named t, initialized using the second constructor.
I have never seen this before, and I've been programming in C++ for years. Thanks for showing me yet another corner case of the language!
For an official explanation: According to the C++03 ISO spec, §6.8:
There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion (5.2.3) as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration.
(My emphasis). In other words, any time C++ could interpret a statement as either an expression (the temporary object cast) or as a declaration (of a variable), it will pick the declaration. The C++ spec explicitly gives
T(a);
As an example of a declaration, not a cast of a to something of type T.
This is C++'s Most Vexing Parse - what looks like an expression is instead getting interpreted as a declaration. I've seen the MVP before, but I have never seen it in this context.
the problem is from constructor you again calling the contructor test(_b)
test::test(){std::cout<<"abc";_b.clear();_b[1]=1;test(_b);}
here is what happens
everytime you call test(_b) it first calls default constructor test::test and it in turns calls the test(_b) and the loop goes on and on untill the stack overflows.
remove the test(_b) from the default constructor
I'm pretty sure that you are not actually "calling the constructor" since they are not directly callable IIRC. The legalese had to do with constructors not being named functions - I don't have a copy of the Standard handy or I might quote it. I believe what you are doing with test(_b) is creating an unnamed a temporary which invokes the default constructor again.
I'm not familiar with the particularities of the standard, but it may be that calling a constructor within a constructor is undefined. As such it could be compiler dependent. In this particular case it causes infinite recursion of your default constructor without ever calling your constructor with the map argument.
C++ FAQ 10.3 has an example with a constructor that has two parameters. If you add an int parameters to your second constructor such as test(map, int), it exhibits a somewhat normal behaviour.
For good form I would simply change test::test(std::map <int, int>& im) for test::testInit(std::map <int, int>& im), and test(_b) to testInit(_b).
Related
In my C++ class we are learning to use function objects and the like, but now we got a code snippet that works on teacher's compiler but not on ours (we use different OS's).
We tested the code snippet below with several compilers (MSVC, clang) and they all reject it, a bit minimized:
#include <functional>
struct Fraction {
Fraction();
Fraction(int z, int n);
Fraction(Fraction&);
// various data members
};
struct FractionComparator {
int operator()(Fraction a, Fraction b) {
return 1;
}
};
int main() {
std::function<int(Fraction, Fraction)> comparator = FractionComparator();
}
We get on clang on macOS:
No viable conversion from 'FractionComparator' to 'function<int (Fraction, Fraction)>'
We already found out that adding a move constructor solves the problem, but we have no idea why this difference exists and why this code doesn't compile on our compilers.
Any ideas?
Why does adding a move-constructor solve the problem?
Fraction is attempted to be copy-constructed from an rvalue.
But constuctor Fraction(Fraction&); takes a non-constant reference. Non-const references are not allowed to bind to temporaries.
The proper constructor signature should be:
Fraction(const Fraction&);
When you declare a move constructor compiler will move-construct Fraction from an rvalue instead.
Why doesn't this code compile on our compilers, but compiles on the teacher's?
This code compiles with VC++.
It looks like the compiler is not conforming to the standard here.
I could find this StackOverflow question with some more detail. It seems to be a compiler extension that allows this to compile.
If compiler extensions are disabled via /Za flag it will not compile anymore.
Starting from C++14 the constructor you are trying to use does not participate in overload resolution unless the target function is callable with the given set of arguments (with std::declval<>() arguments of given types). In your case that would be std::declval<Fraction>() arguments.
Your FractionComparator functor is not callable with std::declval<Fraction>() arguments since it receives its arguments by value, while temporary objects of type Fraction cannot be copied: Fraction's copy-constructor's argument is declared as a non-const reference.
Declare your copy constructor as
Fraction(const Fraction &);
and the code will compile. If you have a good reason to keep it as non-const, then you will have to explore other opportunities for making this work. Why does your FractionComparator insist on receiving its parameters by value anyway?
Your question is tagged C++11, but apparently your compiler is retroactively implementing this C++14 requirement even in C++11 mode.
#include <initializer_list>
#include <vector>
struct test
{
using t = std::vector<test>;
test(t const &v)
{
}
test(t &&v)
{
}
test(std::initializer_list<test> v)
: test{t{v}} //error
{
}
};
Both Clang and GCC complain that the third constructor, the one taking the initializer list, delegates to itself. I don't understand how this is possible though, because you can't construct an initializer list from a vector.
It is trivial to fix the error by replacing the outer curly braces with round parenthesis, but why would this be an issue in the first place? This almost identical program compiles just fine:
#include <initializer_list>
struct a {};
struct b {};
struct test
{
test(a const &)
{
}
test(a &&)
{
}
test(std::initializer_list<b> v)
: test{a{}} //no error, still using curly braces
{
}
};
Interestingly, with the above second example, the error reappears if you substitute b with test. Can someone explain what is going on here?
The type of t{v} is std::vector<test>. The idea is that init-list constructors are always preferred wrt any other constructors, so test{t{v}} will first try to call an init-list constructor, if one exists, and if the types are compatible. In your case, this is possible, since test itself can be implicitly constructed from a std::vector<test> (via your first 2 constructors), so the compiler ends up delegating to the init-list constructor, hence the error.
In the second case, there is no ambiguity, since the type a{}is not implicitly convertible anymore to std::initializer_list<b>.
Make the constructors explicit in the first example, or call the base constructor with test(t{v}) instead, and your ambiguity will disappear (the compiler won't perform the implicit conversion anymore).
A simpler example (live here) that exhibits essentially the same behaviour as your first example is:
#include <initializer_list>
struct test
{
/*explicit*/ test(int){} // uncomment explicit and no more errors
test( std::initializer_list<test> v)
: test{42} {} // error, implicitly converts 42 to test(42) via the test(int)
};
int main(){}
The relevant part of the standard that deals with init-list constructors is §13.3.1.7/1 [over.match.list] - citation below taken from a now-deleted answer of #Praetorian -
When objects of non-aggregate class type T are list-initialized such that 8.5.4 specifies that overload resolution is performed according to the rules in this section, overload resolution selects the constructor in two phases:
— Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
— If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements
of the initializer list.
I'm no C++ expert but the main difference is that
test{a{}}
Does not have an overload for initializer_list<a> so that constructor is not available.
On the other hand test{t{v}} does have an initializer_list<test> constructor available to it because you can create a test from vector. It can use the (I don't know the name of the rule) 1 cast transformation.
test{t{v}} -> test{test(t{v})}
The problem in your code is that you're writing a function calling itself.
test(std::initializer_list<test> v)
: test{t{v}} //error
{
}
test{t{v}} will first call the initializer-list of vector<test> with v as parameter. But vector will call the function again to initialize the value which will fail.
The compiler doesn't know how to resolve the problem. Changing the initialization to use parentheses will (as you said) fix this because it will then call an implicit copy constructor in the vector (doing nothing because the your structure isn't doing anything).
The second example starts with this call: a{}
It is resolved fine because a is a basic structure with implicitly defined constructors. The second call is the test{...} one
Because the type is a and there is a constructor for a it runs just fine.
It was suggested by a team member that using an intializer like this:
return Demo{ *this };
was better than:
return Demo(*this);
Assuming a simple class like this:
class Demo {
public:
int value1;
Demo(){}
Demo(Demo& demo) {
this->value1 = demo.value1;
}
Demo Clone() {
return Demo{ *this };
}
};
I admit to having not seen the { *this } syntax before, and couldn't find a reference that explained it well enough that I understood how the two options differed. Is there a performance benefit, a syntax choice, or something more?
Your colleague is missing a trick with "uniform initialization", there is no need for the type-name when it is known. E.g. when creating a return value. Clone could be defined as:
Demo Clone() {
return {*this};
}
This will call the Demo copy constructor as needed. Whether you think this is better or not, is up to you.
In GOTW 1 Sutter states as a guideline:
Guideline: Prefer to use initialization with { }, such as vector v = { 1, 2, 3, 4 }; or auto v = vector{ 1, 2, 3, 4 };, because it’s more consistent, more correct, and avoids having to know about old-style pitfalls at all. In single-argument cases where you prefer to see only the = sign, such as int i = 42; and auto x = anything; omitting the braces is fine. …
In particular, using braces can avoid confusion with:
Demo d(); //function declaration, but looks like it might construct a Demo
Demo d{}; //constructs a Demo, as you'd expect
The brace syntax will use a constructor that takes an initializer list first, if one exists. Otherwise it will use a normal constructor. It also prevents the chance of the vexing parse listed above.
There is also different behaviour when using copy initialization. With the standard way
Demo d = x;
The compiler has the option to convert x to a Demo if necessary and then move/copy the converted r-value into w. Something similar to Demo d(Demo(x)); meaning that more than one constructor is called.
Demo d = {x};
This is equivalent to Demo d{x} and guarantees that only one constructor will be called. With both assignments above explicit constructors are cannot be used.
As mentioned in the comments, there are some pitfalls. With classes that take an initializer_list and have "normal" constructors can cause confusion.
vector<int> v{5}; // vector containing one element of '5'
vector<int> v(5); // vector containing five elements.
This is just another syntax for calling your copy constructor (actually, for calling a constructor taking what is in the braces as parameters, in this case, your copy constructor).
Personally, I would say it's worse than before simply because it does the same... it just relies on C++ 11. So it adds dependencies without benefits. But your mileage may vary. You will have to ask your colleague.
I must admit that I'd never seen that before.
WikiPedia says this about C++11 initializer lists (search for "Uniform initialization"):
C++03 has a number of problems with initializing types. There are several ways to initialize types, and they do not all produce the same results when interchanged. The traditional constructor syntax, for example, can look like a function declaration, and steps must be taken to ensure that the compiler's most vexing parse rule will not mistake it for such. Only aggregates and POD types can be initialized with aggregate initializers (using SomeType var = {/stuff/};).
Then, later, they have this example,
BasicStruct var1{5, 3.2}; // C type struct, containing only POD
AltStruct var2{2, 4.3}; // C++ class, with constructors, not
// necessarily POD members
with the following explanation:
The initialization of var1 behaves exactly as though it were aggregate-initialization. That is, each data member of an object, in turn, will be copy-initialized with the corresponding value from the initializer-list. Implicit type conversion will be used where necessary. If no conversion exists, or only a narrowing conversion exists, the program is ill-formed. The initialization of var2 invokes the constructor.
They also have further examples for the case where initialiser list constructors were provided.
So based on the above alone: For the plain-old-data struct case, I don't know if there is any advantage. For a C++11 class, using the {} syntax may help avoid those pesky scenarios where the compiler thinks you're declaring a function. Maybe that is the advantage your colleague was referring to?
Sorry for comming late to this discussion but I want to add some points about the different types of initialization not mentioned by others.
Consider:
struct foo {
foo(int) {}
};
foo f() {
// Suppose we have either:
//return 1; // #1
//return {1}; // #2
//return foo(1); // #3
//return foo{1}; // #4
}
Then,
#1, #3 and #4 might call the copy/move constructor (if RVO isn't performed) whereas #2 won't call the copy/move constructor.
Notice that the most popular compilers do perform RVO and thus, in practice, all return statements above are equivalent. However, even when RVO is performed a copy/move constructor must be available (must be accessible to f and defined but not as deleted) for #1, #3 and #4 otherwise the compiler/linker will raise an error.
Suppose now that the constructor is explicit:
struct foo {
explicit foo(int) {}
};
Then,
#1 and #2 don't compile whereas #3 and #4 do compile.
Finally, if the constructor is explicit and no copy/move constructor is available:
struct foo {
explicit foo(int) {}
foo(const foo&) = delete;
};
none of the return statements compile/link.
This is known as list-initialization. The idea is that in C++11, you will have uniform initialization across the board, and avoid ambiguity where the compiler might think you may be making a function declaration (also known as a vexing parse). A small example:
vec3 GetValue()
{
return {x, y, z}; // normally vec(x, y, z)
}
One reason you would want to avoid list-initialization is where your class takes an initializer list constructor that does something different than you would expect.
struct my
{
my(){ std::cout<<"Default";}
my(const my& m){ std::cout<<"Copy";}
~my(){ std::cout<<"Destructor";}
};
int main()
{
my m(); //1
my n(my()); //2
}
Expected output :
1 ) Default
2 ) Copy
Actual output :
What's wrong with my understanding of the constructor invoking mechanism?
Note I have omitted header files for brevity.
Case 1)
m is interpreted as a function return my and taking no arguments.
To see the expected output remove () i.e use my m;
Case 2)
This is something better known as the "Most vexing parse".
n is interpreted as a function returning my that takes an argument of type pointer to function returning my taking no arguments.
To see the expected output in this case try my n((my())); [Instead of treating as an argument specification as in the former case the compiler would now interpret it as an expression because of the extra ()]
My interpretation:
my n((my())) is equivalent to my n = my(). Now the rvalue expression my() creates a temporary[i.e a call to the default constructor] and n is copy initialized to that temporary object[no call to the copy-ctor because of some compiler optimization]
P.S: I am not 100% sure about the last part of my answer. Correct me if I am wrong.
Like Prasoon, I suspect the C++ compiler is parsing your code in a way you don't expect. For example, I think it is parsing the line
my m();
as a function prototype declaration, not as a variable declaration and call to the constructor - hence why you see no output.
The following C++ code does nothing (using GCC 4.4.3) - it does not print the text:
struct MyStruct { MyStruct() { cout << "Hello" << endl; } };
void foo() {
MyStruct ();
}
I think this is not so obvious... Let alone the danger of forgetting to give a variable name. Is there a compiler option/warning to forbid compilation of such code or is there any hidden secret behind allowing it?
Edit: I am sorry. The version above MyStruct(); acutally prints. The version which is not printing is:
void bar() {
MyStruct a();
}
So now I am a bit confused.
This is not a declaration, because in MyStruct ();, the MyStruct would be part of the decl-specifier-seq and forms a type-name therein. And then () can only be a function-declarator. This requires that there is a declarator-id specified, which in your case is not. A special syntactical form is needed to allow such a syntax in declaring a constructor. But such syntactical exceptions are not made in a declaration-statement.
So this construct cannot be a declaration. It is parsed as an expression which specifies a functional cast creating a temporary of type MyStruct.
If the compiler does not print Hello it is either non-conforming or you are not calling foo in your program.
Your edit also does not specify a declaration without a name. It instead specifies a declaration that does have a name. It declares a function that is called a. The compiler has no way that you meant something else by this.
MyStruct a();
It could in an effort deduce this by having a recovering rule when it later discovers errors in your code such as the following
a.f();
If you have this in your code to try and call a member function and "a" is a function, the compiler could check to see if MyStruct contains a member f such that this expression is well-formed. But what if you just forgot to place parentheses? The following would be valid for the above declared function that returns a MyStruct, assuming a suitably declared member f.
a().f();
So in effect, the compiler can't really know what you mean.
You don't have "a declaration with no name" in your code. You have a completely valid expression MyStruct(). It is not a declaration, once again, it is an expression statement. If it doesn't print anything, it mist be the effect of optimization: in C++ it is generally allowed to eliminate temporaries, even if their constructors/destructors have side effects. (Although this context is not really one where such elimination is allowed. Are you sure you actually execute that expression statement?)
MyStruct a(); declares a function a that takes no arguments and returns a MyStruct.
I think the temporary is elided [due to compiler optimization], hence you don't see the call to the c-tor.
Your code is syntactically perfect so there is no need for the compiler to give a warning [as such].
EDIT [As per the edits in the OP]
MyStruct a();
The above is parsed as the declaration of a function a return a MyStruct object and taking no parameters.
Well, temporary objects are perfectly legals. So there is no reasons to warn here.