std::move 真的有助于让我们免于复制吗?

Ran*_*ngo 3 c++ move-semantics

我无法理解真实的本质std::move

  • 他们说:std::move(object)返回“对该对象的右值引用”。是的,我明白了。
  • 他们还说:使用push_back(std::move(object))而不是push_back(object)避免复制。我没有明白这一点,因为它似乎与下面的示例相矛盾:
#include <utility>      
#include <iostream>     
#include <vector>       
#include <string>       
#include <iomanip>
template <class T> void print(T const & object){
    for (auto var : object){std::cout << ' '<<var;}
    std::cout << '\n';
}
int main () {
  std::string foo = "foo-string";
  std::string bar = "bar-string";
  std::vector<std::string> myvector = { "super", "vip" , "pro" , "ok" }; // capcity=size=4;

  // this block is just to increase the capacity of the vector
  myvector.push_back( "rango" );      //NOW: capacity = 8 , size =5
  std::cout << &myvector[0] <<'\n';   //check the address of the first element of the vector

  // this block is the point of the problem
  myvector.push_back(foo);                  // copies -> YES!
  myvector.push_back(std::move(bar));       // moves !?!? 

  std::cout << "myvector contains:";
  print(myvector);

  std::cout << &myvector[0] << '\n';   // re-check the address of first element of the vector = still the same.
  std::cout << "the moved-from object: " << std::quoted(bar); 

  return 0;
}
Run Code Online (Sandbox Code Playgroud)
  • 前后向量的第一个元素的地址push_back(std::move(object))是相同的,这意味着最后一个元素的地址push_back必须存储在距第一个元素“固定距离”处(在本例中)
  • 那么如果我们不将对象复制到固定的给定位置,那么我们如何将该对象的值存储到“那个位置”呢?

chr*_*nte 12

让我们来分析一下移动在 C++ 中的实际含义

  • 对于简单类型,它与复制相同。该对象将被逐字节复制到其新位置。
  • 对于不平凡的类型,它可能意味着其他东西,具体取决于移动构造函数的实现方式。std::vector例如,A有一个动态分配的缓冲区,用于存储其元素。std::vector因此,当您从另一个对象移动构造时,std::vector新创建的对象将接管(或窃取,如果您愿意的话)旧对象的缓冲区。但它仍然是一个新对象,并且具有不同的内存位置。

情况std::string变得有点复杂。概念上std::string非常相似std::vector<char>,但它具有所谓的小缓冲区优化(至少在常见实现中)。这意味着,如果字符串低于一定长度,它将存储在std::string对象内,而不是动态分配的缓冲区中。通常阈值是 20 个字符左右。只有较大的字符串才会被放置在免费商店中。因为您的字符串"bar-string"相当短,所以它将被放置在std::string对象内,因此移动会产生字符串的副本。