我有这样的代码:
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;
答案 0 :(得分:5)
问题是你没有很好地实现你的拷贝构造函数。
而不是:
Pair(const Pair & other){};
你写了
Pair(Pair & other){};
这会导致构造函数只接受l值变量,而不接受临时值,因为只有const引用可以绑定到temporaries和r值引用。
这会强制编译器从get返回Pair作为r值引用(移动语义),因为它返回一个临时的,它不知道如何复制它,只知道如何移动它。再次,临时只能通过const引用或r值引用来捕获。
r-value-references不是const - 这是他们的全部存在!将被抓住,他们的内容将被另一个对象窃取。
为了证明我的观点,这里是GCC编译器输出与你的代码(没有const):
http://coliru.stacked-crooked.com/a/c390189089434f30 - 无法编译
和const:
http://coliru.stacked-crooked.com/a/0db0fc767e6f10f2 - 没有编译错误。
除此之外,我建议你看看std::map
实现或类似的类。开发人员之间就operator []
应该是什么样子以及它返回的原因和原因有一些协议。
良好的软件设计比移动sematincs等非常具体的功能更为重要。
答案 1 :(得分:1)
除了删除返回方法的常量
之外是否有任何解决方法?
没有。在这种情况下返回const
值是愚蠢而毫无意义的,因为用户可以随意制作可变副本。您只能通过使const
禁止优化和良好的语义(例如移动语义)。
删除const
不是“解决方法”,无论移动语义是什么问题,都应该做什么。
答案 2 :(得分:0)
您无法移动const
对象,因为移动操作是一种修改。移动时,将旧对象的内容交换为新对象。这反过来又将新对象的不确定值放入旧对象中。如果旧对象为const
,则无法执行此操作,因为您无法写入该对象。
当您使用移动语义时,您希望按值传递。当您通过值传递时,您将制作一个永远不会被访问的副本,以便您可以自由地移动它。请参阅:Is pass-by-value a reasonable default in C++11?