我如何(或者我可以安全地,或者我可以)移动const对象?

时间:2013-02-12 04:10:25

标签: c++ c++11 move-semantics

考虑this代码:

#include <iostream>
#include <string>

using namespace std;


class Movable {
public:
    Movable(const string& name) : m_name(name) { }
    Movable(const Movable& rhs) {
        cout << "Copy constructed from " << rhs.m_name << endl;
    }

    Movable(Movable&& rhs) {
        cout << "Move constructed from " << rhs.m_name << endl;
    }

    Movable& operator = (const Movable& rhs) {
        cout << "Copy assigned from " << rhs.m_name << endl;
    }

    Movable& operator = (Movable&& rhs) {
        cout << "Move assigned from " << rhs.m_name << endl;
    }

private:
    string m_name;
};


int main() {
    Movable obj1("obj1");
    Movable obj2(std::move(obj1));
    obj2 = std::move(obj1);     // For demostration only

    const Movable cObj("cObj");
    Movable tObj(std::move(cObj));
    tObj = std::move(cObj);     // For demonstration only
}

它的输出是:

Move constructed from obj1
Move assigned from obj1
Copy constructed from cObj
Copy assigned from cObj

如您所见,在这些行中,

Movable tObj(std::move(cObj));
tObj = std::move(cObj);     // For demonstration only

我打算将cObj移到tObj(使用赋值运算符的第二步仅用于演示)。但是,正如您在输出中看到的那样,cObj已复制tObj

上面的例子只是一个演示,我不知道这有什么实际用途。但我会问:

  1. 我可以移动const对象吗?
  2. 如果可以的话,这样做是否安全?
  3. 其他:我忘了问。如果我可以移动const对象,我应该如何? (const_cast?)

2 个答案:

答案 0 :(得分:2)

当然,只要对象的非mutable状态不会因为被移动而改变。

也许您有一个对应于文件内容或数据库记录的对象。它在mutable成员中访问时会缓存数据。现在,您可以通过窃取其缓存数据来移动该对象,而无需实际修改对象。因此,对于该对象来说,移动构造函数和移动赋值运算符需要const Record&&,这是有道理的(只要对象可以移动是有道理的)。

这是完全合法的,C ++ 11标准的第12.8p3节规定:

  

X的非模板构造函数是移动构造函数,如果其第一个参数的类型为X&& const X&& volatile X&& ,或const volatile X&&,并且没有其他参数,或者所有其他参数都有默认参数。

和p19:

  

用户声明的移动赋值运算符X::operator=是类X的非静态非模板成员函数,其中只有一个X&&类型的参数, {{1 }} const X&&volatile X&&

通过这种方式,你可以移动一个const volatile X&&对象,const新的 copy 无论你调用一个实例创建的移动,因此将缓冲区空间重新用于其他内容并避免新的分配,同时保留旧对象并准备好返回其内容(通过再次访问磁盘或数据库)(如果需要)。

答案 1 :(得分:2)

在代码中调用复制构造函数,因为move-constructor需要非const参数(Movable&&),而参数是const对象(std::move(cObj)的类型为const Movable&& })。由于非const rvalue-reference无法绑定const rvalue,因此该重载将被丢弃,下一个最佳匹配是复制构造函数。

现在接下来的问题是,是否/何时可以移出const对象。虽然从技术上讲你可以实现一个带const &&的移动构造函数,你甚至可以在不调用未定义行为的情况下执行此操作(只是不修改源对象的任何非可变成员)问题是它是否有意义。我不认为它。

移动构造函数的存在通常表明存在由对象维护的资源,当不再需要源对象时,该资源可以有效地传输到另一个对象(例如,构造对象时)暂时的)。移动固有地修改源对象。不修改源对象的移动构造函数不能将资源从源对象移动到目标对象,它几乎没有任何意义。