如何(或者我可以安全地,或者我可以)移动const对象
How do I (or can I safely, or may I) move a const object?
考虑以下代码:
#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
。
上面的例子只是一个演示,我不知道它有什么实际用途。但我会问:
- 我可以移动
const
对象吗 - 如果可以的话,这样做安全吗
附加:我忘了问。如果我可以移动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 &&
的移动构造函数,甚至可以在不调用未定义行为的情况下实现(只是不要修改源对象的任何不可变成员),但问题是它是否有意义。我不这么认为。
移动构造函数的存在通常表明,当不再需要源对象时(例如,当从临时对象构建对象时),对象维护的资源可以有效地转移到另一个对象。移动本质上是修改源对象。不修改源对象的移动构造函数不能将资源从源对象移动到目标对象,这几乎没有意义。
- 函数向量_指针有不同的原型,我可以构建一个吗
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- extern可以解决这个问题吗,或者我可以通过其他方法解决这个问题吗?
- 我可以在不声明变量类型的情况下获取输入,或者在 c++ 中为同一变量声明多个类型吗?
- 我可以在生成文件中为 CC、CFLAGS 使用其他名称,或者将它们硬连接到 GNU make 中
- 我可以让 std::list 按顺序插入新元素吗?或者必须使用std::sort
- 我可以将 std::数组转换为切片吗?或者我还能用什么
- 我可以通过 G++ 将 CUDA 与C++程序一起使用吗?或者 CUDA 只能使用 GCC 编译
- 这是openMP的正确用法吗?(或者:我可以信任默认设置吗?)
- 我必须创建一个对象来调用类方法吗?或者我可以只键入类名吗
- 我是否应该复制std::函数,或者我可以总是引用它
- 我是否应该保留随机分布对象实例,或者我可以总是重新创建它
- 最少的c++学习(或者我可以跳过的)
- 我可以(a)不通过输入迭代器写入,或者(b)只通过一个迭代器读取一次吗?
- 我可以声明一个未知类型的特征矩阵吗,或者至少声明一个泛型矩阵并稍后实例化吗
- 如何(或者我可以安全地,或者我可以)移动const对象
- 对于对象的映射,我可以放置对象,或者只是成对