使用 const 对象移动语义

move semantics with const object

我有这样的代码:

class Pair{
public:
    Pair(Pair && other){};

    Pair(Pair & other){};
};

class IROList{
public:
    virtual const Pair get(const char *key) const = 0;

    inline const Pair operator[](const char *key) const{
        return this->get(key);
        // error: binding ‘const Pair’ to reference of type ‘Pair&&’ discards qualifiers
    }
};

编译时,生成

error: binding ‘const Pair’ to reference of type ‘Pair&&’ discards qualifiers

如果我将移动构造函数更改为 const,错误就会消失。

    Pair(const Pair && other){};

但是,如果移动构造函数采用const,我就无法真正移动数据。我应该复制它。

除了删除返回方法的 const 之外,是否有任何解决方法,例如

    virtual Pair get(const char *key) const = 0;
    inline Pair operator[](const char *key) const;

您不能移动 const 对象,因为移动操作是一种修改。当您移动时,您将旧对象的内容交换到新对象中。这又将新对象的不确定值放入旧对象中。如果旧对象是 const,则无法执行此操作,因为您将无法写入它。

当您使用移动语义时,您希望按值传递。当您按值传递时,您会创建一个永远不会被访问的副本,因此您可以自由地从它移动。参见:Is pass-by-value a reasonable default in C++11?

问题是你没有很好地实现你的拷贝构造函数。

而不是:

Pair(const Pair & other){};

你写了

Pair(Pair & other){};

这会导致构造函数只接受左值变量,而不接受临时变量,因为只有 const 引用可以绑定到临时变量和右值引用。

这会强制编译器 return 将 get 作为 r 值引用(移动语义)配对,因为它 return 是临时的,它不知道如何复制它,只是如何移动它。同样,只能通过 const 引用或 r-value-reference 捕获临时文件。

r-value-references 不是 const - 这是它们的全部存在!被抓住,他们的内容将被另一个对象窃取。

为了证明我的观点,这里是 GCC 编译器输出你的代码(无常量):
http://coliru.stacked-crooked.com/a/c390189089434f30 - 不编译

和const:
http://coliru.stacked-crooked.com/a/0db0fc767e6f10f2 - 没有编译器错误。

除此之外,我建议您查看 std::map 实施或类似 类。开发人员之间就 operator [] 应该是什么样子、return 应该是什么样子以及为什么这样达成了一些共识。 良好的软件设计远比移动语义等非常具体的功能重要。

Is there any workaround except removing the const of returning methods

没有。在这种情况下返回 const 值是愚蠢且毫无意义的,因为用户可以随意制作一个可变副本。您只能通过使其成为 const.

来禁止优化和良好的语义(例如移动语义)

删除 const 不是 "workaround",这是无论移动语义问题如何都应该做的事情。