copy vs std :: move for thets

Per*_*kie 25 c++ move-semantics c++11

  • 在该示例中,默认副本和std :: move之间有什么区别?
  • move对象之后,新旧对象之间是否存在依赖关系?
int main () {

    int a = 100;
    std::cout<<&a<<std::endl;

    auto a_copy = a;                 // deduced as int
    std::cout<<&a_copy<<std::endl;

    auto a_move = std::move(a);      // deduced as int
    std::cout<<&a_move<<std::endl;

};
Run Code Online (Sandbox Code Playgroud)

输出:

0x7fffffffe094
0x7fffffffe098
0x7fffffffe09c
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 27

这个例子中,没有区别.我们最终得到int的是价值为100的3 秒.但是不同的类型肯定会有所不同.例如,让我们考虑一下vector<int>:

std::vector<int> a = {1, 2, 3, 4, 5}; // a has size 5
auto a_copy = a;                      // copy a. now we have two vectors of size 5
auto a_move = std::move(a);           // *move* a into a_move
Run Code Online (Sandbox Code Playgroud)

最后一个变量a_move取得了a内部指针的所有权.所以我们最终得到的a_move是一个大小为5的向量,但a现在是空的.它move比a更有效copy(想象一下,如果它是一个1000字符串的向量 - a_copy将涉及分配一个1000字符串的缓冲区并复制1000个字符串,但a_move只需指定几个指针).

对于其他一些类型,一个可能无效:

std::unique_ptr<int> a{new int 42};
auto a_copy = a;            // error
auto a_move = std::move(a); // OK, now a_move owns 42, but a points to nothing
Run Code Online (Sandbox Code Playgroud)

对于许多类型,但没有区别:

std::array<int, 100> a;
auto a_copy = a;            // copy 100 ints
auto a_move = std::move(a); // also copy 100 ints, no special move ctor
Run Code Online (Sandbox Code Playgroud)

更普遍:

T a;
auto a_copy = a;            // calls T(const T& ), the copy constructor
auto a_move = std::move(a); // calls T(T&& ), the move constructor
Run Code Online (Sandbox Code Playgroud)

  • @LightnessRacesinOrbit你更喜欢看`std :: move`重命名为`std :: rref`吗?因为我知道我会 - "std :: move"极具误导性. (3认同)
  • @Barry:是的,我们去了; 这可能是我记得的.我认为这是一个被各种高调类型承认几次的观点(而不是仅限于cprogramming.com上的论坛帖子).也就是说,"它意味着意图"是一个可爱的原则,可以在简单的脚本语言中很好地工作,但它完全违背了逻辑(更不用说已建立的范例),就像C++一样灵活. (3认同)
  • 移动后,矢量"a"不保证为空. (3认同)
  • @Person.Junkie是的,`std::move`只是对右值引用执行静态转换,但绝对更喜欢`std::move()`而不是编写转换 - 它(a)更少的打字,(b)使意图代码行更加清晰。 (2认同)
  • @Barry:我不同意 - 虽然它更短,但却是_lie_. (2认同)

Dru*_*nix 11

使用std::move只是将左值更改为xvalue,因此它适用于移动构造函数和移动赋值运算符.对于内置类型,这些不存在,因此在此示例中使用move没有任何区别.


jua*_*nza 6

在该示例中,默认副本和std :: move之间有什么区别?

没有区别.复制某些内容满足移动的要求,对于内置类型,移动实现为副本.

移动后,对象是新旧之间的依赖关系

不,没有依赖关系.两个变量都是独立的.

  • @ Person.Junkie:演员本身并没有引起任何"重大进步".强制转换允许程序员方便地指示他们想要一个被调用的_different_函数来实现数据传输:通常,我们编写"移动构造函数"来移动而不是复制,例如通过交换内部指针.这可能会导致_huge_改进,但是`std :: move`本身并没有这样做.你可以在带有标签和各种其他技术的C++ 03中完成它,它只是不太方便(并且不能一般地工作,例如标准库容器中的元素). (7认同)
  • @ Person.Junkie这太宽泛了.有关于此的全文.但基本上,有些类型移动便宜,复制费用昂贵.在这些情况下,移动可能有一个优势.此外,有些东西不是可复制的,但可能是可移动的(例如文件流或唯一指针). (5认同)
  • @ Person.Junkie在这儿?没有优势.缺点是代码令人困惑. (2认同)

mbg*_*gda 6

为了扩展其他发帖人的答案,move-is-a-copy 范式也适用于由 POD 类型组成(或由 POD 类型组成的其他类型组成)的所有数据结构,如下例所示:

struct Foo
{
    int values[100];
    bool flagA;
    bool flagB;
};

struct Bar
{
    Foo foo1;
    Foo foo2;
};

int main()
{
    Foo f;
    Foo fCopy = std::move(f);
    Bar b;
    Bar bCopy = std::move(b);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在两者的情况下FooBar没有有意义的方式将数据从一个移动到另一个,因为两者最终都是 POD 类型的聚合 - 它们的数据都不是间接拥有的(指向或引用其他内存)。因此,在这些情况下,移动将作为副本实现,而原件 ( f, b) 在行上的分配之后保持不变std::move()

移动语义只能通过动态分配的内存或独特的资源来有意义地实现。