I just learned about guaranteed copy elision in C++17. According to the answer on that question:
When you do
return T();
, this initializes the return value of the function via aprvalue
. Since that function returns T, no temporary is created; the initialization of theprvalue
simply directly initializes the return value.The thing to understand is that, since the return value is a
prvalue
, it is not an object yet. It is merely an initializer for an object, just likeT()
is.
So I was wondering, does this work for anything other than:
T f() {return T();}
T t = f();
So I wrote this code with emplace_back
to test it:
#include <vector>
#include <iostream>
struct BigObj{
BigObj() = default;
BigObj(int) { std::cout << "int ctor called" << std::endl; }
BigObj(const BigObj&){
std::cout << "copy ctor called" << std::endl;
}
BigObj(BigObj&&){
std::cout << "move ctor called" << std::endl;
}
};
BigObj f(){ return BigObj(2); }
int g(){ return 2; }
int main(){
std::vector<BigObj> v;
v.reserve(10);
std::cout << "emplace_back with rvalue \n";
v.emplace_back(1+1);
std::cout << "emplace_back with f()\n";
v.emplace_back(f());
std::cout << "emplace_back with g()\n";
v.emplace_back(g());
}
This is the output I get (with copy elision disabled):
emplace_back with rvalue
int ctor called
emplace_back with f()
int ctor called
move ctor called
emplace_back with g()
int ctor called
It seems that the move constructor is still called even though a prvalue
is passed directly into emplace_back
, which I thought could be used to directly construct an object instead of being used to construct a temporary and then moving it.
Is there a more elegant way to avoid the move constructor call with emplace_back
other than doing something like what the g()
function does?
It seems that the move constructor is still called even though a prvalue is passed directly into emplace_back
You think you do, but you don't pass it into the function. You give it a prvalue as argument, yes, but what emplace_back
accepts is a pack of forwarding references. A reference must refer to an object, so a temporary is materialized, and moved.
The correct way to use emplace_back
is to pass it the arguments for initializing the object in place. That way you don't need to move the element type of the vector (though you may need to move/copy the arguments).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With