3
#include <iostream>

class Class
{
    public:
    Class() { std::cerr << "ctor" << std::endl; }
    ~Class() { std::cerr <<"dtor" << std::endl; }

    Class(Class&)  { std::cerr << "copy ctor" << std::endl; }
    Class & operator=(const Class &)
    {
            std::cerr << "copy operator=" << std::endl;
            return *this;
    }

    Class(Class&&) { std::cerr << "move ctor" << std::endl;}
    Class & operator=(Class &&)
    {       
            std::cerr << "move operator="<< std::endl;
            return *this;
    }
 };

int main(int, char**)
{
    Class object;
    Class && rvr = Class(); 
    object = rvr; // (*)
}

Output is

ctor
ctor
copy operator=
dtor
dtor

1) Why "copy ctor" is called at line (*)?

2) If i have to use std::move() every-time, what is the difference between "move semantics" and any method that will move data, like object.destructive_move();?

3) when exactly move ctor/operator is called?

thanks!

4

2 回答 2

7

在 (*) 行不调用复制 ctor,而是调用复制赋值运算符。我想这就是你的意思。

调用的是复制赋值运算符而不是移动赋值运算符,因为rvr它是左值。请注意,表达式的类型与它是否是左值是正交的。

如果您将赋值语句修改为object = Class();or object = static_cast<Class&&>(rvr),您会发现调用了移动赋值运算符,因为在这两种情况下 RHS 是一个右值。

这种行为是明智的:比如说,考虑一个移动赋值运算符的实现。它的参数具有类型右值引用,但它仍然是一个左值。如果它是一个右值,那么第一次使用参数可能会修改其状态以成为一个“空”对象(移动语义),然后第二次使用该参数可能无法按预期工作。

它的实际工作方式是,std::move当您想以一种使其保持“空”状态的方式使用参数时,您将明确使用。

于 2012-07-01T17:07:35.760 回答
3
Class && rvr = Class(); 

我要说的没有意义,但这是 C++11 规则。

rvr是一个变量,它是对 a 的右值引用Class。这很容易理解。但重要的是要理解这一点:命名变量永远不是右值表达式。即使它是一个右值引用!

再说一次,我知道这没有意义,但这是规则。右值引用变量不是右值表达式

临时是一个右值表达式,所以Class()给你一个右值。从函数返回的临时值也是一个右值表达式,所以如果你有一些Class按值返回的函数,你会得到一个右值返回。

这很重要,因为如果您有两个基于左值和右值引用重载的函数(如复制/移动构造函数/赋值),则只有当表达式类型是右值时,C++11 才会选择右值引用版本。

这就是std::move存在的原因。它的存在是为了明确说明您何时想要移动某物。它通过将您给它的值转换为右值表达式来做到这一点。即,它返回Class&&.

这是真正令人困惑的部分。如果您有一个命名的右值引用变量,那不是右值表达式。但是如果你有一个未命名的右值引用,比如Class&&从一个函数返回,那就是一个右值表达式

std::move返回Class&&。所以如果你想从一个命名变量中移动,你必须总是调用std::move它。所以如果你想从 移动rvr,你必须这样做:

object = std::move(rvr); // (*)

这将返回一个Class&&to rvr。将发生 C++11 重载决议。由于参数 tooperator=是一个右值表达式,它将选择 的右值引用版本operator=。从而调用了一个动作。

请注意,这std::move实际上只是半复杂演员表的包装。它不会移动;它是operator=移动的。

于 2012-07-01T20:00:14.007 回答