返回无法按值复制的对象

时间:2015-02-25 12:00:48

标签: c++ copy-constructor c++14 copy-elision

我有一个对象,其复制操作太慢,所以我决定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必须是非常量的,因为它将在以后改变。

如何处理?

3 个答案:

答案 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
}