C++ 在这个C++;一小条

C++ 在这个C++;一小条,c++,constructor,copy-constructor,C++,Constructor,Copy Constructor,在这个问题中,我们必须找出复制构造函数被调用了多少次, 根据我的说法是5,但答案是7。这是怎么发生的 Widget f(Widget u) { Widget v(u); Widget w = v; return w; } int main() { Widget x; Widget y = f(f(x)); } 在禁用复制省略和移动的情况下,有: 1) 小部件y=f(f(x)) 在f函数中有4个复制构造函数的调用 1) u按值传递 2) v是从u复制初

在这个问题中,我们必须找出复制构造函数被调用了多少次, 根据我的说法是5,但答案是7。这是怎么发生的

Widget  f(Widget  u)
{
    Widget v(u);
    Widget w = v;
    return w;
}
int main()
{
    Widget x;
    Widget y = f(f(x));
}

在禁用复制省略和移动的情况下,有:

1) 小部件y=f(f(x))

f
函数中有4个复制构造函数的调用

1)
u
按值传递

2)
v
是从
u
复制初始化的

3)
w
是从
v
复制初始化的

4)
w
在返回时复制

所以,实际上有9个电话


启用复制省略后,gcc/clang上有5个调用。

+1-赋值
小部件y=f(f(x))

+2-调用函数
f()
两次,通过值而不是引用传递参数。

+2-复制
v(u)
调用两次

+2-复制初始化
小部件w=v
调用两次

等于7

请注意,对于某些设置下的某些编译器,这是正确的。其他答案也是正确的,my解释了为什么结果可能是7,例如,您可以在
bcc32
下获得

根据我的说法,一个复制构造函数被调用了多少次 答案是7。这是怎么发生的

Widget  f(Widget  u)
{
    Widget v(u);
    Widget w = v;
    return w;
}
int main()
{
    Widget x;
    Widget y = f(f(x));
}
将代码段更新为实际工作的代码后(请参见底部),您可以看到以下输出(test.cpp中的代码):

我们只需要看看单个函数调用是如何工作的。为此,我们有:

Widget  f(Widget  u)
{
        Widget v(u);
        Widget w = v;
        return w;
}

y = f(x)
在以下情况下调用复制选择器:

  • 按值将
    x
    发送到
    f
  • f
    中从
    u
    创建
    v
  • v
    分配到
    w
    f
  • f
  • f
    的返回值赋值给
    y
因此,对于
f
的每次调用,我们需要使用copy-ctor
4次,由于
f
被调用两次,您已经有
+8次
copy-ctor调用,
+1次
用于
y
中的最终赋值,总共
9次

但是为什么我们在上面的输出中只看到5个呢? 答案是:优化

GCC正在通过优化删除一些复制操作。如果我们使用
-fno-elide构造函数
标志构建它,我们可以看到所有这些:

➜  /tmp  g++ -fno-elide-constructors -o -std=c++11 test test.cpp && ./test
def ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
copy ctor
这告诉GCC不要执行我们之前构建中看到的优化,它显示了
x
使用的默认构造函数下面的所有复制构造函数调用

使用的代码段
#包括
使用名称空间std;
类小部件{
公众:

Widget(){你不能在调试器中运行它并跟踪每一步吗?除此之外,请发布一个最小但完整的Widget定义。你能说出你找到了哪5个,这样我们就可以更容易地告诉你你错过了哪5个吗?(请注意,准确的数字取决于复制省略、移动语义等)每个
f(x)不是只有3个吗
call+1 for
y
assignment?您按值调用函数,并在函数内部进行两次复制。您按值将参数传递给函数,这样就生成了一个副本。如果您使用的函数类似于
f(Widget&u)
你会得到5份副本。没问题。让我把它转化为一个答案。OP得到了7份-我假设他在静态变量中计算了这一份,或者在构造函数中计算了输出。所以我们在这里看到了复制省略。我猜这是返回期间的副本,在这里被省略了。我认为这一份缺少了函数运行时由
f
创建的副本“代码”>返回< /COD>语句。这个答案似乎不正确。考虑不应该返回值优化来处理这个问题吗?阅读我的文章并具体看<代码> FNO-ELIDE构造函数< /COD>基于旗标的东西。确实,你对G++是正确的。但是答案应该是7,它在某些编译器下面。对于7,找到一个E.X.Bcc32编译器。复制了7份。这个问题不是很好,因为它没有指定环境。我同意这个问题不是很好,但是说答案“应该是7”在我看来仍然是不正确的。7是特定编译器进行一些优化的结果,但是如果我们走这条路,我们永远不会得到“正确的”回答b/c有很多不同的编译器。你需要告诉你的编译器不要优化那样的东西(就像我对
g++
所做的那样),然后才能看到所有的copy-ctor调用。是的,我也有同样的问题,但我认为正如M.M.所指出的,存在一些版本问题“注意:C++03中的答案与C++11中的答案不同,除非小部件是不可移动的;您询问的是哪个版本?”@BijonGuha:使用
-std=C++11
标志显示没有区别,并且是您在注释中声明使用的,那么为什么您仍然说这是“版本差异”“根据你的信息,我的帖子是准确的。是的,你是正确的。因为我只是一个初学者,所以我没有那么多想法。即使我也不知道这意味着什么”-std=c++11”。但当我在编译器中运行你的代码时,我得到了5。说真的,我也完全搞不清楚发生了什么。如果你对我在帖子中提到的事情有什么具体问题,请告诉我。落选者能否解释他/她的落选理由?
#include <iostream>
using namespace std;

class Widget {

public:
        Widget() { cout << "def ctor" << endl; }
        Widget(const Widget &other) { cout << "copy ctor" << endl; }
};

Widget  f(Widget u)
{
        Widget v(u);
        Widget w = v;
        return w;
}

int main()
{
        Widget x;
        Widget y = f(f(x));
        return 0;
}