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;
}
程序仍然打印一个单词copying
,表示激活了副本构造函数。那么在哪里调用构造函数?为什么函数不返回对o1
的引用,以便修改res
的值也会改变o1
的值?
答案 0 :(得分:8)
复制是在语句中完成的:
auto res = Min(o1, o2);
Min()
的返回类型为const Obj&
。上面的auto
将推导为Obj
,而不是const Obj&
(即res
类型将为Obj
)。 res
是对象,它是通过复制构造函数(即Obj::Obj(const Obj&)
)初始化的,因此将进行复制构造。
如果您改为写:
auto& res = Min(o1, o2)
res
将是const Obj&
类型,并且在那里不会进行复制构造,因为res
将是引用,而不是对象。
答案 1 :(得分: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是具有简历资格的类型,则将类型A的顶级cv限定词用于类型推导。
- 如果P是引用类型,则将P引用的类型用于类型推导。
所以下面的语句中的
auto res = Min(o1, o2);
将res
推导出为Obj
,从而在分配时调用复制构造函数。
因此将以上内容修改为此:
auto& res = Min(o1, o2);
将使auto
推论res
为const Obj&
。
但是,如果您执行此操作,则res
不能被修改,因为它是const
的引用