简体   繁体   中英

Best way to use emplace_back to avoid move constructor call?

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 a prvalue . Since that function returns T, no temporary is created; the initialization of the prvalue 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 like T() 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM