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

How do I (or can I safely, or may I) move a const object?

本文关键字:我可以 或者 移动 const 对象 安全 如何      更新时间:2023-10-16

考虑以下代码:

#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. 如果可以的话,这样做安全吗

附加:我忘了问。如果我可以移动const对象,我应该如何操作?(const_cast?)

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

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

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

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

和p19:

用户声明的移动赋值运算符X::operator=是类X的非静态非模板成员函数,仅具有一个类型为X&&const X&&volatile X&&const volatile X&&的参数。

通过这种方式,您可以移动const对象,reopen新的副本,无论您称之为通过移动创建的实例,从而将缓冲区空间重新用于其他对象并避免新的分配,同时保持旧对象不变,并准备在需要时返回其内容(通过再次访问磁盘或数据库)。

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

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

移动构造函数的存在通常表明,当不再需要源对象时(例如,当从临时对象构建对象时),对象维护的资源可以有效地转移到另一个对象。移动本质上是修改源对象。不修改源对象的移动构造函数不能将资源从源对象移动到目标对象,这几乎没有意义。

相关文章: