C++11 - 移动语义在构造上很慢

use*_*612 3 c++ struct move-semantics c++11

这段代码

#include <iostream>
#include <vector>

struct obj
{
  std::string name;
  int age;
  float money;

  obj():name("NO_NAME"),age(0),money(0.0f){}
  obj(const std::string& _name, const int& _age, const float& _money):name(_name),age(_age),money(_money){}

  obj(obj&& tmp): name(tmp.name), age(tmp.age), money(tmp.money) {}
  obj& operator=(obj&&) {return *this;}

};

int main(int argc, char* argv[])
{
  std::vector<obj> v;
  for( int i = 0; i < 5000000; ++i )
  {
    v.emplace_back(obj("Jon", 45, 500.6f));
  }
  return(0);
}
Run Code Online (Sandbox Code Playgroud)

比等效的 with 慢大约 2 倍v.push_back(obj("Jon", 45, 500.6f));,我不明白为什么。

我已经用 botg++ 4.7.2clang++ 3.3.

我错在哪里?


现在我已经更正了我的移动构造器,我将添加更多

这是一个 push_back 版本

这是 emplace_back 版本

我正在用timeLinux 下的实用程序测试这 2并用

g++-4.7 -std=c++11 -s -O3 -DNDEBUG
Run Code Online (Sandbox Code Playgroud)

或者

clang++ -std=c++11 -s -O3 -DNDEBUG
Run Code Online (Sandbox Code Playgroud)

R. *_*des 5

什么都不做比较好。你试图让它更快(比什么更快?你写移动构造函数之前你真的分析了吗?),但你打破了它。

编译器免费生成复制和移动构造函数和赋值运算符,她做得对。通过决定自己编写,你告诉编译器你知道得更好,所以她只是让开,让你自己改进打破它。

你破坏的第一件事是你让你的移动构造函数实际上是copy。有名字的东西是左值,即使左值是右值引用,也不能隐式移动。所以初始化程序需要实际调用std::move.

你破坏的第二件事是你没有让移动构造函数声明它不会通过添加noexcept来抛出。编译器生成了这个。通过不声明不抛出异常,std::vector在重新分配底层存储时, 的实现可能不会使用移动:如果不保证移动不会抛出,它就无法提供强大的异常保证。

做这一切会让它表现得更好吗?也许。也许不吧。您的实现可能正在对 进行小字符串优化std::string,这意味着没有动态分配:整个字符串"Jon"很小,将直接存储在std::string对象中。这使得移动具有与副本相同的成本。

您可以obj通过动态分配并使用unique_ptr. 即使在存在小字符串优化的情况下,这也会使移动比副本更便宜。但是,您正在以分配和额外间接访问的成本为这种廉价付出代价。这是否是可取的,或者不是只有你可以判断。