I wanted to see the difference between push_back and emplace_back, as in several places I read recommendation as now it's better to use emplace_back as "it can do all push_back can do and more", so I expect ti to be more efficient. But to my surprise
#include <iostream>
#include <vector>
class A
{
public:
A() {std::cout << "A const" << std::endl;}
~A() {std::cout << "A dest" << std::endl;}
A(const A& a) {std::cout << "A copy const" << std::endl;}
A(A&& a) {std::cout << "A move const" << std::endl;}
A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
A& operator=(A&& a) {std::cout << "A move operator=" << std::endl; return *this; }
};
int main () {
std::vector<A> va;
std::cout <<"push:" << std::endl;
va.push_back(A());
std::cout <<std::endl<< "emplace:" << std::endl;
va.emplace_back(A());
std::cout <<std::endl<< "end:" << std::endl;
return 0;
}
Output is
push:
A const
A move const
A dest
emplace:
A const
A move const
A copy const
A dest
A dest
end:
A dest
A dest
emplace_back calls move constructor and then copy one when push_back calls only one move const. I checked with g++ (Ubuntu 7.4.0-1ubuntu1~16.04~ppa1) 7.4.0 and online C++ shell.
Am I missing something?
push_back is not more efficient, and the results you observe are due to the vector resizing itself.
When you call emplace after push_back, the vector has to resize itself to make room for the second element. This means that it has to move the A that was originally inside the vector, making emplace appear more complex.
If you reserve enough space in the vector beforehand, this doesn't happen. Notice the call to va.reserve(2) after va's creation:
#include <iostream>
#include <vector>
class A
{
public:
A() {std::cout << "A const" << std::endl;}
~A() {std::cout << "A dest" << std::endl;}
A(const A& a) {std::cout << "A copy const" << std::endl;}
A(A&& a) {std::cout << "A move const" << std::endl;}
A& operator=(const A& a) {std::cout << "A copy operator=" << std::endl; return *this; }
A& operator=(A&& a) {std::cout << "A move operator=" << std::endl; return *this; }
};
int main () {
std::vector<A> va;
// Now there's enough room for two elements
va.reserve(2);
std::cout <<"push:" << std::endl;
va.push_back(A());
std::cout <<std::endl<< "emplace:" << std::endl;
va.emplace_back(A());
std::cout <<std::endl<< "end:" << std::endl;
return 0;
}
The corresponding output is:
push:
A const
A move const
A dest
emplace:
A const
A move const
A dest
end:
A dest
A dest
Can we make things even more efficient? Yes! emplace_back takes whatever arguments you provide it, and forwards them to A's constructor. Because A has a constructor that takes no arguments, you can also use emplace_back with no arguments! In other words, we change
va.emplace_back(A());
to
va.emplace_back(); // No arguments necessary since A is default-constructed
This results in no copy, and no move:
push:
A const
A move const
A dest
emplace:
A const
end:
A dest
A dest
A note on vectors resizing: It's important to note that the implementation of std::vector is smart. If A had been a trivially copyable type, std::vector might have been able resize in-place without additional copying using a system function similar to realloc. However because As constructors and destruction contain code, realloc can't be used here.
Related
For the following example, why the vector move operation is not triggered? How do I know when I should explicitly use a move operator?
#include <iostream>
#include <vector>
using namespace std;
class Test {
public:
Test() {
std::cout << " default " << std::endl;
}
Test(const Test& o) {
std::cout << " copy ctor " << std::endl;
}
Test& operator=(const Test& o) {
std::cout << " copy assign " << std::endl;
return *this;
}
Test(Test&& o) {
std::cout << " move ctor" << std::endl;
}
Test& operator=(Test&& o) {
std::cout << " move assign " << std::endl;
return *this;
}
};
int main()
{
std::cout << " vector: " << std::endl;
std::vector<Test> p;
p = {Test()}; // expect vector move here since the RHS is temporary.
std::cout << std::endl;
std::cout << " single value " << std::endl;
Test tt;
tt = Test();
}
Output:
vector:
default
copy ctor
single value
default
default
move assign
I was under the impression that when we assign a temporary variable to a lvalue (the single value case in the example), it would trigger a move operation if it exists. Seems that I was wrong and my understanding was overly simplified, I need to carefully check case by case to ensure there's no redundant copy.
std::vector has an assignment operator that takes an std::initializer_list:
vector& operator= (initializer_list<value_type> il);
So when you wrote p = {Test()}; you're actually using the above assignment operator.
Now why a call to the copy constructor is made can be understood from dcl.init.list, which states:
An object of type std::initializer_list<E> is constructed from an initializer list as if the implementation allocated a temporary array of N elements of type const E, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std::initializer_list object is constructed to refer to that array.
#include <iostream>
class A {
public:
A() { std::cout << "Constructor" << std::endl; }
A(const A& a) { std::cout << "Copy Constructor" << std::endl; }
A& operator=(const A& a) { std::cout << "Copy = operator" << std::endl; }
A(A&& a) { std::cout << "Move Constructor" << std::endl; }
A& operator=(A&& a) { std::cout << "Move = operator" << std::endl; }
~A() { std::cout << "Destructor" << std::endl; }
};
void f(A&& a) { std::cout << "function" << std::endl; }
int main() {
f(A());
return 0;
}
The output of the following program is:
Constructor
function
Destructor
Why is the move-constructor not called here? It seems like copy elision occurs even if I compile with the flag -fno-elide-constructors: g++ test.cpp -fno-elide-constructors -std=c++11
Short answer: You are not move-constructing anything.
You are just creating a temporary Aobject and then passing a reference to it. If you want to see move construction, you could e.g. change the signature of f to
void f(A a)
I have the following code:
#include <iostream>
#include <vector>
struct A
{
std::vector<int> x;
A()
{
std::cout << "A()" << std::endl;
}
A(const A&)
{
std::cout << "A(const A&)" << std::endl;
}
~A()
{
std::cout << "~A()" << std::endl;
}
};
struct B : public A
{
std::vector<int> y;
B()
{
std::cout << "B()" << std::endl;
}
B(const A&a)
{
std::cout << "B(const A&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const A&&a)
{
std::cout << "B(const A&&)" << std::endl;
x = std::move(a.x);
y.resize(x.size());
}
B(const B&)
{
std::cout << "B(const B&)" << std::endl;
}
~B()
{
std::cout << "~B()" << std::endl;
}
};
A ret_a()
{
A a;
a.x.resize(10);
return a;
}
int main()
{
std::cout << "section I" << std::endl << std::endl;
A a = ret_a();
B b(a);
std::cout << "a.x.size=" << a.x.size() << std::endl;
std::cout << std::endl << "section II" << std::endl << std::endl;
B b2(ret_a());
std::cout << "b.x.size=" << b.x.size() << std::endl;
std::cout << std::endl << "section III" << std::endl << std::endl;
return 0;
}
With output (VS2013, Release build)
section I
A()
A()
B(const A&)
a.x.size=10
section II
A()
A()
B(const A&&)
~A()
b.x.size=10
section III
~B()
~A()
~B()
~A()
~A()
Why a.x.size() within "section I" has size 10? I thought that std::move should move all data from a.x to y.x
Why did "section II" call constructor A() twice? I thought that B(const A&&) would prevent excessive copying of A
UPDATE
see fixed code at http://pastebin.com/70Nmt9sT
T&& and const T&& are not the same type. You almost never want a const rvalue reference - you can't steal its resources since you made it const! x = std::move(a.x); in B(const A&a) copies a.x since the return type of std::move(a.x) is const vector<int>&&.
The constructor, B(const A&&) calls the default constructor of A since it is derived from A, and the member initializer list does not make an attempt to construct the base A. This is the second A call.
Why a.x.size() within "section I" has size 10? I thought that std::move should move all data from a.x to y.x
This is because of B(const A&& a). Since a is const within that constructor, you only have const access to its member x, and calling std::move on a vector<T> const results in a vector<T> const&& which cannot bind to vector's move constructor (which takes a vector<T>&& argument). Instead it ends up calling the copy constructor, which leaves the source object unmodified.
Why did "section II" call constructor A() twice? I thought that B(const A&&) would prevent excessive copying of A
The first default construction occurs within the body of ret_a(). The second default construction is that of the A sub-object of B. To avoid the second one move the A instance in the member initializer list.
B(const A&&a)
: A(std::move(a))
{
std::cout << "B(const A&&)" << std::endl;
y.resize(x.size());
}
Note that the move doesn't actually result in moving the contents of a due to the same reason as explained above. Moreover, even modifying the signature to B(A&& a) would not result in the contents of a being moved because the user provided copy constructor and destructor definitions prevent implicit generation of a move constructor for A, and it'll be copied instead.
Hi I created a class Foo with a noexcept move constructor using gcc 4.7 and set the vector reserve size to 2 so that it would have to reallocate the size when adding the 3rd item. It seems it is calling the copy constructor instead of the move constructor when doing this. Am I missing something here?
#include <vector>
#include <iostream>
class Foo
{
public:
Foo(int x) : data_(x)
{
std::cout << " constructing " << std::endl;
}
~Foo()
{
std::cout << " destructing " << std::endl;
}
Foo& operator=(const Foo&) = default;
Foo& operator=(Foo&&) = default;
Foo(Foo&& other) noexcept : data_(std::move(other.data_))
{
std::cout << " Move constructing " << std::endl;
}
Foo(const Foo& other) noexcept : data_(other.data_)
{
std::cout << " Copy constructing " << std::endl;
}
private:
int data_;
};
int main ( int argc, char *argv[])
{
std::vector<Foo> v;
v.reserve(2);
v.emplace_back(1);
std::cout << "Added 1" << std::endl;
v.emplace_back(2);
std::cout << "Added 2" << std::endl;
v.emplace_back(3);
std::cout << "Added 3" << std::endl;
std::cout << "v size: " << v.size() << std::endl;
}
output:
constructing
Added 1
constructing
Added 2
constructing
Copy constructing
Copy constructing
destructing
destructing
Added 3
v size: 3
destructing
destructing
destructing
After tinkering with it a bit with both GCC 4.7 and 4.8, it seems that it is indeed a bug in 4.7, which only appears when the class' destructor is not marked noexcept:
struct Foo {
Foo() {}
~Foo() noexcept {}
Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; }
Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; }
};
int main() {
std::vector<Foo> v;
v.reserve(2);
v.emplace_back();
v.emplace_back();
v.emplace_back();
}
GCC 4.7 displays:
move constructor
move constructor
If we remove noexcept from the destructor:
struct Foo {
Foo() {}
~Foo() {}
Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; }
Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; }
};
GCC 4.7 displays:
copy constructor
copy constructor
GCC 4.8 uses the move constructor in both cases.
I have compiled this code with vs2011. It prints first constructor then copy constructor.
But if I change the function to return a instead of ap, it will move the object. Is this a bug or why does it behave like this? Is *ap not a rvalue?
struct A
{
A() { cout << "constructor" << endl;}
A(const A&) { cout << "copy constructor " << endl;}
void operator=(const A&) { cout << "assignment operator" << endl; }
A( A&&) { cout << "move copy constructor" << endl;}
void operator=(A&&) { cout << "move assignment operator" << endl;}
};
A func() { A a; A *ap = &a; return *ap; }
int main()
{
A a = func();
return 0;
}
*ap is an lvalue (ยง 5.3.1.1, n3290) which is in general not safe for the move to happen automatically. The local variable return a; is a different case. There's no requirement for the compiler to prove that in this specific instance it would be safe. This is another good reason for not using pointers in cases where you don't really want pointer semantics.
Changing it to:
return std::move(*ap);
will cause it to be explicitly moved however.