当我尝试返回引用时,为什么我的对象仍然被复制

coi*_*ung 4 c++ pass-by-reference lvalue auto c++11

class Obj {
public:
    Obj(int aa, int bb): a(aa), b(bb) {}
    Obj(const Obj& o) {a = o.a; b = o.b;std::cout << "copying" << std::endl;}
    Obj(Obj&& o) {a = o.a; b = o.b;std::cout << "moving" << std::endl;}
    int a;
    int b;
};
const Obj& Min(const Obj &o1, const Obj &o2) {
    if (o1.a > o2.a) {
        return o1;
    } else {
        return o2;
    }
}
int main() {
    using namespace std;

    auto o1 = Obj(1,1);
    auto o2 = Obj(2,2);
    auto res = Min(o1, o2);

    cout << res.a << endl;
    res.a = 100;
    cout << o1.a << endl;
    cout << o2.a << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序仍会打印一个单词copying,表示复制构造函数已激活.那么构造函数在哪里?为什么函数不返回引用,o1以便修改值res也会改变值o1

眠りネ*_*ネロク 8

副本在声明中完成:

auto res = Min(o1, o2);
Run Code Online (Sandbox Code Playgroud)

Min()返回类型是const Obj&.在auto上述将被推断为Obj,不const Obj&(即,res类型将是Obj).res,它是一个对象,通过复制构造函数(即Obj::Obj(const Obj&))初始化,因此发生了复制结构.

如果你改写:

auto& res = Min(o1, o2)
Run Code Online (Sandbox Code Playgroud)

res将是类型,const Obj&并且不会在那里进行复制构造,因为res它将是引用,而不是对象.


P.W*_*P.W 5

这与auto推断类型的方式有关:

从CPP工作草案(N4713):

10.1.7.4.1占位符类型推导[dcl.type.auto.deduct]
...
4.如果占位符是自动类型说明符,则使用模板参数推导的规则确定推断类型T'替换T.

和:

17.9.2.1从函数调用中减去模板参数[temp.deduct.call]
...
2.如果P不是引用类型:
...
(2.3) - 如果A是cv限定类型,则顶级类型推导忽略了A类型的cv限定符.

  1. 如果P是引用类型,则P引用的类型用于类型推导.

所以auto在下面的声明中

auto res = Min(o1, o2);
Run Code Online (Sandbox Code Playgroud)

推导res作为Obj由此进行的分配拷贝构造函数.

所以修改上面这个:

auto& res = Min(o1, o2);
Run Code Online (Sandbox Code Playgroud)

将能够auto演绎resconst Obj&.

但是如果你这样做,res不能在main中进行修改,因为它是一个const参考