有人可以解释这个 C++ 程序的输出吗?
Can someone explain the output of this c++ program?
为什么输出 foo3
等于 3
?
我建议,当调用 bar(foo1)
时,函数 bar
在堆栈上创建 foo1
的副本,因此它的值等于 0,当返回此值时,副本- foo3
的构造函数再次递增该值,所以它应该是 2?
提前致谢。
这是我的代码:
#include <iostream>
struct Foo {
Foo()
: x(0)
{
}
Foo(const Foo& foo)
: x(foo.x + 1)
{
}
int x;
};
Foo bar(Foo foo)
{
foo.x++;
return foo;
}
int main()
{
Foo foo1;
Foo foo2 = foo1;
std::cout << "A:" << foo1.x << std::endl;
std::cout << "B:" << foo2.x << std::endl;
Foo foo3 = bar(foo1);
std::cout << "C:" << foo3.x << std::endl;
}
输出:
A:0
B:1
C:3
我相信这里有三个复制构造函数在起作用,行 foo2 = foo1
,foo1
到 bar
的传递,以及 foo1
从 bar
.
修改您的代码可以清楚地了解正在发生的事情:
#include <iostream>
struct Foo {
Foo()
: x(0)
{
std::cout << "Constructor called" << std::endl;
}
Foo(const Foo& foo)
: x(foo.x + 1)
{
std::cout << "Copy constructor called" << std::endl;
}
int x;
};
Foo bar(Foo foo)
{
std::cout << "B2:" << foo.x << std::endl;
foo.x++;
return foo;
}
int main()
{
Foo foo1;
Foo foo2 = foo1;
std::cout << "A:" << foo1.x << std::endl;
std::cout << "B:" << foo2.x << std::endl;
Foo foo3 = bar(foo1);
std::cout << "C:" << foo3.x << std::endl;
}
输出:
Constructor called
Copy constructor called
A:0
B:1
Copy constructor called
B2:1
Copy constructor called
C:3
当您创建第一个 foo1
时,它的 x
为零。对 bar
的调用按值传递,因此它被复制 - 因此 bar
中的参数值为 1。函数 bar
本身将 x
进一步递增 1,所以现在是 2。最后,return 语句再次按值 returns,所以还有另一个副本 - 因此最终的 x
是 3.
注意 RVO 在这里不适用,因为 Foo
不是按值 returning 局部变量 - 而是 returning 参数,必须实际复制。
根据标准 [class.copy/31],允许复制省略的情况,特别排除函数参数为 returned:
的情况
— in a return statement in a function with a class return type, when
the expression is the name of a non-volatile automatic object (other
than a function or catch-clause parameter) with the same cv-unqualified
type as the function return type, the copy/move operation can be
omitted by constructing the automatic object directly into the
function’s return value
0 -> 1
你把foo1
复制到bar
的参数里.
1 -> 2
您在 bar
内递增 x
。
2 -> 3
您将 bar
复制到临时 return 值。
我数三个增量。
做的时候:
Foo foo2 = foo1;
您正在调用复制构造函数,因此 foo2.x 的值为 1。
然后调用时:
Foo foo3 = bar(foo1);
因为您没有通过引用传递 'bar' 的参数,所以使用复制构造函数 (x == 1) 将 foo1 的副本创建到 bar 中。之后该副本的 x 成员递增(x == 2)并最终返回。返回时不会创建另一个副本,因为 'return value optimization'(still x == 2)。
最后 foo3 再次使用 copy ctor(x == 3).
初始化
为什么输出 foo3
等于 3
?
我建议,当调用 bar(foo1)
时,函数 bar
在堆栈上创建 foo1
的副本,因此它的值等于 0,当返回此值时,副本- foo3
的构造函数再次递增该值,所以它应该是 2?
提前致谢。
这是我的代码:
#include <iostream>
struct Foo {
Foo()
: x(0)
{
}
Foo(const Foo& foo)
: x(foo.x + 1)
{
}
int x;
};
Foo bar(Foo foo)
{
foo.x++;
return foo;
}
int main()
{
Foo foo1;
Foo foo2 = foo1;
std::cout << "A:" << foo1.x << std::endl;
std::cout << "B:" << foo2.x << std::endl;
Foo foo3 = bar(foo1);
std::cout << "C:" << foo3.x << std::endl;
}
输出:
A:0
B:1
C:3
我相信这里有三个复制构造函数在起作用,行 foo2 = foo1
,foo1
到 bar
的传递,以及 foo1
从 bar
.
修改您的代码可以清楚地了解正在发生的事情:
#include <iostream>
struct Foo {
Foo()
: x(0)
{
std::cout << "Constructor called" << std::endl;
}
Foo(const Foo& foo)
: x(foo.x + 1)
{
std::cout << "Copy constructor called" << std::endl;
}
int x;
};
Foo bar(Foo foo)
{
std::cout << "B2:" << foo.x << std::endl;
foo.x++;
return foo;
}
int main()
{
Foo foo1;
Foo foo2 = foo1;
std::cout << "A:" << foo1.x << std::endl;
std::cout << "B:" << foo2.x << std::endl;
Foo foo3 = bar(foo1);
std::cout << "C:" << foo3.x << std::endl;
}
输出:
Constructor called
Copy constructor called
A:0
B:1
Copy constructor called
B2:1
Copy constructor called
C:3
当您创建第一个 foo1
时,它的 x
为零。对 bar
的调用按值传递,因此它被复制 - 因此 bar
中的参数值为 1。函数 bar
本身将 x
进一步递增 1,所以现在是 2。最后,return 语句再次按值 returns,所以还有另一个副本 - 因此最终的 x
是 3.
注意 RVO 在这里不适用,因为 Foo
不是按值 returning 局部变量 - 而是 returning 参数,必须实际复制。
根据标准 [class.copy/31],允许复制省略的情况,特别排除函数参数为 returned:
的情况— in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value
0 -> 1
你把foo1
复制到bar
的参数里.1 -> 2
您在bar
内递增x
。2 -> 3
您将bar
复制到临时 return 值。
我数三个增量。
做的时候:
Foo foo2 = foo1;
您正在调用复制构造函数,因此 foo2.x 的值为 1。 然后调用时:
Foo foo3 = bar(foo1);
因为您没有通过引用传递 'bar' 的参数,所以使用复制构造函数 (x == 1) 将 foo1 的副本创建到 bar 中。之后该副本的 x 成员递增(x == 2)并最终返回。返回时不会创建另一个副本,因为 'return value optimization'(still x == 2)。 最后 foo3 再次使用 copy ctor(x == 3).
初始化