我有一个对象,其复制操作太慢,所以我决定delete
它并迫使用户只移动。无论如何,这个物体的副本都很有意义。但后来我有了这个功能:
Object loadFromFile(const std::string& name) {
Object obj;
...
return obj;
}
即使复制省略发生在这里并且没有调用复制构造函数,也无法编译,因为复制构造函数必需存在且可访问。这是我的第二次尝试:
Object&& loadFromFile(const std::string& name) {
Object obj;
...
return std::move(obj);
}
这个编译。耶!
但是当尝试使用它时,一个新问题激增:
Object x = loadFromFile("test.txt");
这又需要一个复制构造函数。即使使用move,我也无法让它工作:
Object x = std::move(loadFromFile("test.txt"));
我遇到的唯一解决方案是:
const Object& x = loadFromFile("test.txt");
但是x
必须是非常量的,因为它将在以后改变。
如何处理?
答案 0 :(得分:3)
这个错了:
Object&& loadFromFile(const std::string& name) {
Object obj;
...
return std::move(obj);
}
您正在返回对局部变量的引用,这是未定义的行为。物体死亡,你返回的是对你的鼻子的引用,所以恶魔可以从它出来。
第二个是对的:
Object loadFromFile(const std::string& name) {
Object obj;
...
return obj;
}
实际上,在这种情况下,首先执行查找,就好像obj
是一个右值(标准12.8.32):
当满足复制/移动操作的省略标准时,但不满足异常声明,并且要复制的对象由左值指定,或当返回语句中的表达式为(可能是括号)id-expression命名一个对象,其中包含在最内层封闭函数或lambda-expression的body 或parameter-declaration-clause中声明的自动存储持续时间,重载决策选择复制的构造函数首先执行,好像对象是由右值指定。如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值。 [注意:无论是否发生复制省略,都必须执行此两阶段重载决策。 如果未执行elision,则确定要调用的构造函数,并且即使调用被取消,也必须可以访问所选构造函数。 - 后注]
应选择move-constructor Object(Object&&)
。
答案 1 :(得分:2)
Ops,我的错,抱歉。
我删除了复制构造函数,但实际上没有实现移动,假设它已经存在。创建移动构造函数可以解决问题。
感谢@Joseph Mansfield的光。
答案 2 :(得分:0)
你能把它作为输出参数传递吗? 类似的东西:
void loadFromFile(const std::string& name, Object& obj) {
//Operations on obj
}