我想通过函数调用创建一个对象,我只会使用一次。
我试过的两种方法给出了相同的结果,但由于我是C ++的新手,我不确定它们是否合适。
#include <iostream>
using namespace std;
struct Foo {
Foo(const int x, const int y): x(x), y(y) {};
Foo(Foo & myfoo): x(myfoo.x), y(myfoo.y) {
cout << "copying" << endl;
};
const int x, y;
};
int sum(const Foo & myfoo) {
return myfoo.x + myfoo.y;
}
Foo make_foo(const int x, const int y) {
Foo myfoo (x, y);
return myfoo;
}
int main () {
// version 1
cout << 1 + sum(Foo(2,3)) << endl;
// version 2
cout << 1 + sum(make_foo(2,3)) << endl;
}
这些方法中的哪一种“更正确”?有什么不同?我用gcc和clang运行上面的代码,两次都得到了
6
6
表示复制构造函数未被调用。
相关: Calling constructors in c++ without new
编辑:谢谢,我已经知道了RVO。我只是想知道一种方法是否比其他方法更受欢迎
答案 0 :(得分:2)
在这种情况下,这两种方法是等效的。
您所观察的是Copy elision,或更具体地Return Value Optimization。
编译器非常聪明,可以识别您不需要构建中间实例,因为您只是要复制,然后销毁它。因此,它只是创建最终实例,它是函数返回的目标。
语言标准明确允许此优化,即使这意味着您的副本构造函数被绕过。换句话说,无法保证调用复制构造函数的功能。
答案 1 :(得分:0)
复制构造函数未被调用,因为在sum(const Foo & myfoo)
中,myfoo
正在通过引用传递,因此不需要复制。恕我直言我会说Foo
的一般适用的构造函数足以创建一个实例。如果你有专门的功能会使你的Foo类与构造函数混乱,那么在其他地方使用函数可能会更优雅,比如Foo loadFooFromFile(string filename)
答案 2 :(得分:0)
值得注意的是,通常以make_*
命名的函数对于需要模板参数的类型非常有用(并且可以在构造期间推导出它们)。
在C ++类中,在调用构造函数时不会推导出模板参数(这将在C ++ 17中更改),因此您必须手动键入它们。通过创建一个创建对象的函数,您可以自动为它推导出它。
例如,查找std::tuple
或std::pair
我发现了一个非常相关的主题 Deduction of the function
答案 3 :(得分:0)
在第一种情况下,cout&lt;&lt; 1 + sum(Foo(2,3))&lt;&lt; ENDL;由于sum接受Foo引用,因此不会调用复制构造函数。对于以后的情况,您的编译器正在执行RVO,因此不会调用复制构造函数。有关详情,请阅读Return Value Optimization和Copy Elision。 this question还有更多细节。