通过C ++中的函数调用创建对象

时间:2016-07-06 16:37:43

标签: c++

我想通过函数调用创建一个对象,我只会使用一次。

我试过的两种方法给出了相同的结果,但由于我是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。我只是想知道一种方法是否比其他方法更受欢迎

4 个答案:

答案 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::tuplestd::pair

修改

我发现了一个非常相关的主题 Deduction of the function

答案 3 :(得分:0)

在第一种情况下,cout&lt;&lt; 1 + sum(Foo(2,3))&lt;&lt; ENDL;由于sum接受Foo引用,因此不会调用复制构造函数。对于以后的情况,您的编译器正在执行RVO,因此不会调用复制构造函数。有关详情,请阅读Return Value OptimizationCopy Elisionthis question还有更多细节。