What's the difference between doing
A a{ A() };
and,
A a( A{} );
to avoid the Most Vexing Parse? When should I use a particular one?
The two syntaxes are equivalent in most situations, and which one to choose is mostly a matter of taste. If you are into uniform initialization, I would suggest doing:
A a{ A{} };
Otherwise, parentheses alone can be used to disambiguate:
A a((A())); // This can't be parsed as a function declaration
Notice, that there is one situation (very unlikely, I must say) where the two forms shown in your question are not equivalent. If your class A has a constructor that takes an initializer_list<A>, that constructor will be favored over the copy constructor when the braces are used:
#include <initializer_list>
#include <iostream>
struct A
{
A() { }
A(std::initializer_list<A> l) { std::cout << "init-list" << std::endl; }
A(A const& a) { std::cout << "copy-ctor" << std::endl; }
};
int main()
{
A a(A{}); // Prints "copy-ctor" (or nothing, if copy elision is performed)
A b{A()}; // Prints "init-list"
}
The above difference is shown in this live example.
In most situations they are equivalent, but A a{ A() }; will prefer a std::initializer_list constructor if one is present, while A a( A{} ); will prefer a move/copy constructor.
When the construct ends up calling a move/copy constructor, the construction of the new object can be elided, but this is not possible for a std::initializer_list constructor.
Neither syntax will ever be parsed as a function declaration, so both avoid the most-vexing-parse.
#include <iostream>
#include <initializer_list>
struct A {
A() {
std::cout << "A()\n";
}
A(A&&) {
std::cout << "A(A&&)\n";
}
A(std::initializer_list<A>) {
std::cout << "A(std::initializer_list<A>)\n";
}
};
int main()
{
{A a{ A() };} // Prints "A()\n" "A(std::initializer_list<A>)\n"
{A a( A{} );} // Prints "A()\n" and *possibly*
// (depending on copy elision) "A(A&&)\n"
}
Related
I want to return a tuple containing types like std::vector or std::unordered_map etc. where the objects may be large enough that I care about not copying. I wasn't sure how copy elision / return value optimization will work when the returned objects are wrapped in a tuple. To this end I wrote some test code below and am confused by parts of its output:
#include <tuple>
#include <iostream>
struct A {
A() {}
A(const A& a) {
std::cout << "copy constructor\n";
}
A(A&& a) noexcept {
std::cout << "move constructor\n";
}
~A() {
std::cout << "destructor\n";
}
};
struct B {
};
std::tuple<A, B> foo() {
A a;
B b;
return { a, b };
}
std::tuple<A, B> bar() {
A a;
B b;
return { std::move(a), std::move(b) };
}
std::tuple<A, B> quux() {
A a;
B b;
return std::move(std::tuple<A, B>{ std::move(a), std::move(b) });
}
std::tuple<A, B> mumble() {
A a;
B b;
return std::move(std::tuple<A, B>{ a, b });
}
int main()
{
std::cout << "calling foo...\n\n";
auto [a1, b1] = foo();
std::cout << "\n";
std::cout << "calling bar...\n\n";
auto [a2, b2] = bar();
std::cout << "\n";
std::cout << "calling quux...\n\n";
auto [a3, b3] = quux();
std::cout << "\n";
std::cout << "calling mumble...\n\n";
auto [a4, b4] = mumble();
std::cout << "\n";
std::cout << "cleaning up main()\n";
return 0;
}
when I run the above (on VS2019) I get the following output:
calling foo...
copy constructor
destructor
calling bar...
move constructor
destructor
calling quux...
move constructor
move constructor
destructor
destructor
calling mumble...
copy constructor
move constructor
destructor
destructor
cleaning up main()
destructor
destructor
destructor
destructor
So from the above is looks like bar() is best which is return { std::move(a), std::move(b) }. My main question is why foo() ends up copying? RVO should elide the tuple from being copied but shouldn't the compiler be smart enough to not copy the A struct? The tuple constructor could be a move constructor there since it is firing in an expression that is being returned from a function i.e. because struct a is about to not exist.
I also don't really understand what is going on with quux(). I didnt think that additional std::move() call was necessary but I don't understand why it ends up causing an additional move to actually occur i.e. I'd expect it to have the same output as bar().
My main question is why foo() ends up copying? RVO should elide the
tuple from being copied but shouldn't the compiler be smart enough to
not copy the A struct? The tuple constructor could be a move
constructor
No, move constructor could only construct it from another tuple<> object. {a,b} is constructing from the component types, so the A and B objects are copied.
what it going on with quux(). I didnt think that additional
std::move() call was necessary but I don't understand why it ends up
causing an additional move to actually occur i.e. I'd expect it to
have the same output as bar().
The 2nd move happens when you are moving the tuple. Moving it prevents the copy elision that occurs in bar(). It is well-know that std::move() around the entire return expression is harmful.
I am recently having a problem with uniform initialization on C++14 standard. I wrote a code which declares a class having two constructors, first one is parameterized constructor and the other one is a constructor having intializer_list. The code looks as follows,
#include <iostream>
#include <vector>
class MyClass final {
public:
MyClass() = default;
explicit MyClass(const int a, const int b)
: m_a(a)
, m_b(b)
{
std::cout << "From constructor" << std::endl;
};
MyClass(std::initializer_list<int> init_li)
: m_a(init_li[0])
, m_b(init_li[1])
{
std::cout << "Initializer List constructor" << std::endl;
}
void PrintValues() const
{
std::cout << m_a << " " << m_b << std::endl;
}
private:
int m_a, m_b;
}
int
main(void)
{
using namespace std;
vector<int> a{ 1, 2 }; // Creates a vector with initializer list. Very nice.
vector<int> a{ (1, 2) }; // Calls a vector constructor "explicit vector(std::size_t __n, const std::allocator<int> &__a = std::vector<int>::allocator_type())" NOT INITIALIZER LIST constructor. Okay.
MyClass a{ 1, 2 }; // Calls the initializer list constructor. Fine.
MyClass b{ (1, 2) }; // Also calls the initializer list constructor. What???
b.PrintValues();
return 0;
}
So, my question is why can't I call a constructor other than initializer list with uniform initialization in MyClass just like I did in vector with parentheses?
This code:
MyClass a2{ (1, 2) };
could not call the 2 argument constructor. What is happening is that in the expression (1,2), the 1 is evaluated before the comma operator, it is discarded, and the result of the expression is 2. This obviously calls the initializer_list constructor.
Enable warnings, e.g. with -Wall and the compiler will tell you about this.
Note that the same thing happens in the vector<int> a{ (1, 2) }; call. The 1 is discarded, and the constructor of vector that takes a single argument is invoked.
I've come across a case in which type-safe c++ produces non-matching ctor/dtors.
The following code generates two constructors for A. The default constructor also constructs its base (B), but the default-generated copy/move ctor does not construct B. Later, it destroys B, so we get non-matching ctor/dtor.
I've tried this with gcc and clang and both fail. In the gcc bug report forum they suggested this isn't a gcc problem.
I may be missing something, but isn't there something odd when type-safe code results in a dtor call for a class that hasn't been constructed?
Program output:
B() -> INSERT: 0x7fff55398b2f
~B() -> ERASE: 0x7fff55398b2f
~B() -> ERASE: 0x7fff55398b40 // <- unmatched dtor call
Assertion failed: (!all.empty()), function ~B, file gcc_bug.c, line 20.
Code follows:
#include <set>
#include <iostream>
#include <cstdint>
#include <cassert>
#include <experimental/optional>
std::set<std::uintptr_t> all;
struct B
{
B()
{
std::cerr << "B() -> INSERT: " << this << "\n";
all.insert((std::uintptr_t)this);
}
~B()
{
std::cerr << "~B() -> ERASE: " << this << "\n";
assert(!all.empty()); // FAILS
assert(all.find((std::uintptr_t)this) != all.end()); // FAILS
all.erase((std::uintptr_t)this);
}
};
struct A : B {};
static std::experimental::optional<A> f()
{
A a;
return a;
}
int main()
{
auto a = f();
return 0;
}
You have a B being created by the implicitly defined copy constructor. This, of course, is not calling B::B(). If you add the following constructor:
B(const B& other) : B()
{
*this = other;
}
you will see the output:
B() -> INSERT: 0x7ffe57ef918f
B() -> INSERT: 0x7ffe57ef91b0
~B() -> ERASE: 0x7ffe57ef918f
~B() -> ERASE: 0x7ffe57ef91b0
The important point to take away is this: every constructor completely constructs the object. By default, a copy constructor will not call the default constructor (and, obviously, vice versa). Therefore if you have something that needs to be done in every constructor, you must explicitly do that in every constructor, either by direct call, or by constructor chaining.
Consider this:
#include <iostream>
struct A{
A(){
std::cout << "Create empty A" << std::endl;
}
A(const A& a){
// Why is this never called??
std::cout << "Never called" << std::endl;
}
};
A genA() {
A a;
return a;
}
int main(int argc, const char *argv[])
{
A a(genA()); // Expected to call copy constructor
return 0;
}
Why is the copy constructor not called?
What should I do if I want to ensure that "Never called" is printed on the screen every time I copy A.
This is called as Return value optimization.
Compiler can optimize your code so that it bulds the object directly in the location where it would have been copied too. Thus there will be no reason to use the copy constructor.
Note: The standard explicitly allows it do so.
One way you can force the compiler to avoid RVO is to not return by value - e.g.
#include <iostream>
#include <memory>
struct A{
A() {
std::cout << "Create empty A" << std::endl;
}
A(const A& a) {
// This will be called now
std::cout << "Never called" << std::endl;
}
};
std::auto_ptr<A> genA() {
return std::auto_ptr<A>(new A);
}
int main(int argc, const char *argv[])
{
A a(*(genA().get())); // this will trigger the copy-ctor
return 0;
}
Though this is a horrible hack. I would instead ask why you want to do this? and if you are hoping to put some side-effects into the constructor, urge you to think otherwise.
Copy constructor invocations can be elided (even if they contain side effects), the standard allows that ([12.2]).
EDIT:
I suggest that you do not try to fight it in real world code.
If you just want to see the copy ctor executed in some example/turorial code, then it usually helps not to compile with optimization. Some compilers even have switches that help to avoid that. For GCC it should be -fno-elide-constructors.
It seems the way to construct objects in C++0x avoiding copies/moves (particularly for large stack allocated objects) is "pass by lambda".
See the following code:
#include <iostream>
#define LAMBDA(x) [&] { return x; }
class A
{
public:
A() {};
A(const A&) { std::cout << "Copy "; }
A(A&&) { std::cout << "Move "; }
};
class B1
{
public:
B1(const A& a_) : a(a_) {}
B1(A&& a_) : a(std::move(a_)) {}
A a;
};
class B2
{
public:
B2(const A& a_) : a(a_) {}
B2(A&& a_) : a(std::move(a_)) {}
template <class LAMBDA_T>
B2(LAMBDA_T&& f, decltype(f())* dummy = 0) : a(f()) {}
A a;
};
int main()
{
A a;
std::cout << "B1 b11( a ): ";
B1 b11(a);
std::cout << std::endl;
std::cout << "B2 b12(LAMBDA(a)): ";
B2 b12(LAMBDA(a));
std::cout << std::endl;
std::cout << std::endl;
std::cout << "B1 b21( std::move(a) ): ";
B1 b21(std::move(a));
std::cout << std::endl;
std::cout << "B2 b22(LAMBDA(std::move(a))): ";
B2 b22(LAMBDA(std::move(a)));
std::cout << std::endl;
std::cout << std::endl;
std::cout << "B1 b31(( A() )): ";
B1 b31((A()));
std::cout << std::endl;
std::cout << "B2 b32((LAMBDA(A()))): ";
B2 b32((LAMBDA(A())));
std::cout << std::endl;
std::cout << std::endl;
}
Which outputs the following:
B1 b11( a ): Copy
B2 b12(LAMBDA(a)): Copy
B1 b21( std::move(a) ): Move
B2 b22(LAMBDA(std::move(a))): Move
B1 b31(( A() )): Move
B2 b32((LAMBDA(A()))):
Note the "pass by lambda" removes the move in the case where the parameter is a what I believe is called a "prvalue".
Note that it seems the "pass by lambda" approach only helps when the parameter is a "prvalue", but it doesn't seem to hurt in other cases.
Is there anyway to get functions to accept "pass by lambda" parameters in C++0x, that is nicer than the client having to wrap their parameters in lambda functions themselves? (other than defining a proxy macro that calls the function).
If you're okay with a templated constructor, you might as well use perfect forwarding instead of the obfuscation with lambdas.
class super_expensive_type {
public:
struct token_t {} static constexpr token = token_t {};
super_expensive_type(token_t);
}
constexpr super_expensive_type::token_t super_expensive_type::token;
class user {
public:
template<typename... Args>
explicit
user(Args&&... args)
: member { std::forward<Args>(args)... }
{}
private:
super_expensive_type member;
};
// ...
// only one construction here
user { super_expensive_type::token };
super_expensive_type moved_from = ...;
// one move
user { std::move(moved_from) };
super_expensive_type copied_from = ...;
// one copy
user { copied_from };
Using lambdas can't be better than this because the result from the expression in the lambda body has to be returned.
There's a fundamental problem with what you're doing. You cannot magic an object into existence. The variable must be:
Default constructed
Copy constructed
Move constructed
Constructed with a different constructor.
4 is off the table, since you only defined the first three. Your copy and move constructors both print things. Therefore, the only conclusion one can draw is that, if nothing is printed, the object is being default constructed. IE: filled with nothing.
In short, your Lambda-based transfer mechanism doesn't seem to be transferring anything at all.
After further analysis, I see what's happening. Your lambda isn't actually taking a value by reference; it's constructing a value. If you expand the macro, what you get is this:
B2 b32(([&] {return A()}));
It constructs a temporary; it doesn't actually take anything by reference. So I'm not sure how you can consider this "passing" anything. All you're doing is making a function that constructs an object. You could just as easily pass the arguments for B2::a's constructor to the constructor of B2 and have it use them to create the object, and it would give you the same effect.
You're not passing a value. You're making a function that will always create the exact same object. That's not very useful.