C++11 右值并 move : Can legacy code avoid copy?

标签 c++ c++11 move-semantics rvalue-reference call-by-value

请理解,我仍在学习 C++11 的 move 和右值语义的概念。我的问题是遗留代码是否可以通过简单地使用 C++11 编译器和 STL 获得免费午餐来避免不必要的复制。

这是一个非常简单的例子。此代码为给定字符串构建一个简单的字符频率表。例如,“apple”应该返回 {('a', 1), ('e', 1), ('l', 1), ('p', 2)}。正如您将看到的,我只是使用 vector 作为值。

typedef std::tuple<char, int> Frequency;
typedef std::vector<Frequency> Frequencies;

Frequencies buildFrequenciesTable(std::string w) {
  char table['z' - 'a' + 1] = { 0, };
  std::for_each(w.cbegin(), w.cend(), [&table](char c) {
    ++table[::tolower(c) - 'a'];
  });

  Frequencies freqs;
  for (size_t i = 0; i < 'z' - 'a' + 1; ++i) {
    if (table[i] != 0)
      freqs.push_back(tuple<char, int>((char) ('a' + i), table[i]));
  }
  return freqs; // Q1: Is vector get copied?
}

int main() {
  using namespace std;

  Frequencies f1 = buildFrequenciesTable("apple"); // Q2: Copy?
  Frequencies f2 = buildFrequenciesTable("banana");
  vector<Frequencies> fs = { f1, f2 }; // Q3: Copy?
}

很明显,当返回 vector 作为值时,C++03 会生成所有复制代码(使用复制构造函数和赋值运算符)。在 C++11 中呢? std::vector a 具有 move 构造函数。这段代码可以避免任何不必要的拷贝吗?或者,我应该在上面的代码中使用 && 还是 std::forward

我试图调试内部STL代码,但很难说服。

注意:我的目标是尽量减少这些函数中任何不必要的拷贝。我知道我可以使用新的/指针/引用,但这需要解决内存泄漏问题。所以,我想尽可能多地使用值。

最佳答案

对于 Q1,即使在 C++03 中也很可能没有拷贝,因为拷贝已被“命名返回值优化”(NRVO) 删除。

对于 Q2,即使在 C++03 中也很可能没有拷贝,因为复制省略将其删除。

对于 Q3,即使在 C++11 中,您也确实有拷贝,因为您需要将 f1f2 标记为按顺序 move 实际 move 它们:

vector<Frequencies> fs = { std::move(f1), std::move(f2) };

既然你问了多个问题,我想我会省略进一步的解释,查找 NRVO、copy-elision 和需要 std::move 的地方,问你是否有任何进一步的问题。

但是,在某些情况下您可以获得自由 move ,例如,如果有一个可以 move 的临时:

vector<Frequencies> fs = { buildFrequenciesTable("apple"),
                           buildFrequenciesTable("bananas") };

上面的代码会将 buildFrequenciesTable() 返回的两个 vector 检测为临时值,因此它们将被 move 到 fs 中。

关于C++11 右值并 move : Can legacy code avoid copy?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19501182/

相关文章:

c++二维数组问题

c++11:为什么静态 constexpr 的类内初始化不是定义?

c++ - 递归变量容器编译器错误

c++ - 函数模板参数包不在参数列表的末尾

c++ - 检测内存页面大小

c++ - 我的程序有什么方法可以制作任何给定大小的子集?

c++ - 返回常量引用参数而不复制

c++ - 我可以禁止临时对象作为参数吗?

c++ - G++/MSVC++2008 在矩阵实现中调用 inner_product() 的区别

operator-overloading - C++11 重载 `M operator+(M&&,M&&)`