【问题标题】:Creating an object by function call in C++在 C++ 中通过函数调用创建对象
【发布时间】:2016-07-06 16:37:42
【问题描述】:

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

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

【问题讨论】:

  • 我的猜测是编译器通过内联优化make_foo(因为它没有做任何有意义的事情)。在这种情况下,make_foo 甚至没有包含任何程度的复杂含义,我会使用 Foo(2,3)
  • 旁注:为了最佳实践,您的复制构造函数应该通过const Foo&amp;

标签: c++


【解决方案1】:

在这种情况下,这两种方法是等效的。

你观察到的是Copy elision,或者更具体地说是Return Value Optimization

编译器足够聪明,可以识别出您不需要构造中间实例,因为您只是要复制然后销毁它。因此,它只是创建作为函数返回目标的最终实例。

语言标准明确允许这种优化,即使这意味着您的复制构造函数被绕过。换句话说,复制构造函数被调用的功能是无法保证的。

【讨论】:

  • 不能保证......在这种情况下。如果你要做Foo b(make_foo(1, 2)),你保证会调用它来构造b。轻微的挑剔,但 C++ 就是这些。
【解决方案2】:

没有调用复制构造函数,因为在sum(const Foo &amp; myfoo) 中,myfoo 是通过引用传递的,因此不需要复制。恕我直言,我会说Foo 的普遍适用的构造函数足以创建实例。如果您有专门的功能会使您的 Foo 类与构造函数混淆,那么在其他地方有一个函数可能会更优雅,例如Foo loadFooFromFile(string filename)

【讨论】:

  • OP不关心sum调用时的复制操作,而是关注make_foo的返回值
【解决方案3】:

值得注意的是,通常以make_* 命名的函数对于需要模板参数的类型很有用(它们可以在构造过程中推导出来)。

在 C++ 中,调用构造函数时不会推导出类模板参数(这将在 C++17 中更改),因此您必须手动键入它们。通过创建一个创建对象的函数,您可以自动为您推导出它。

例如查找std::tuple,或std::pair

编辑

我发现了一个非常相关的线程 Deduction of the function

【讨论】:

  • 为了将来参考,我不会在答案中使用“编辑”标题。 SO 是要被编辑的,不需要宣布每次编辑。让它看起来像一个更好的答案,如果我们需要,我们可以看到编辑:)
【解决方案4】:

在第一种情况下 cout Return Value Optimization 和 Copy Elisionthis question 也有更多细节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多