如果我编译(在G ++下)并运行以下代码,则打印“Foo :: Foo(int)”。但是,在使复制构造函数和赋值运算符成为私有之后,它无法使用以下错误进行编译:“错误:'Foo :: Foo(const Foo&)'是私有的”。如果它只在运行时调用标准构造函数,它需要一个复制构造函数吗?
#include <iostream>
using namespace std;
struct Foo {
Foo(int x) {
cout << __PRETTY_FUNCTION__ << endl;
}
Foo(const Foo& f) {
cout << __PRETTY_FUNCTION__ << endl;
}
Foo& operator=(const Foo& f) {
cout << __PRETTY_FUNCTION__ << endl;
return *this;
}
};
int main() {
Foo f = Foo(3);
}
答案 0 :(得分:15)
这里使用了复制构造函数:
Foo f = Foo(3);
这相当于:
Foo f( Foo(3) );
其中第一组parens是对复制构造函数的调用。您可以通过说:
来避免这种情况Foo f(3);
请注意,编译器可能会选择优化复制构造函数调用,但复制构造函数仍必须可用(即不是私有的)。无论复制构造函数的实现是什么,C ++标准都特别允许这种优化(参见第12.8 / 15节)。
答案 1 :(得分:2)
你看到的,是标准优化所允许的结果,当编译器避免创建临时的时候。即使存在副作用(如示例中的IO),编译器也可以用简单的结构替换构造和赋值。
但事实上,如果程序形成不良,则不应该依赖于情况,编译器是否进行此优化。这就是为什么
Foo f = Foo(3);
需要复制构造函数。和
Foo f(3);
没有。虽然它可能会导致相同的二进制代码。
引自12.8.15
当符合某些标准时,a 允许实现省略 复制类对象的构造, 即使是复制构造函数和/或 对象的析构函数有侧面 效果。在这种情况下, 实现对待源和 省略的复制操作的目标 仅仅是两种不同的方式 指的是同一个对象,而且 该对象的破坏发生在 两个时代的晚些时候 物体本来就被摧毁了 没有优化.11)这个 复制操作的省略是 允许以下内容 情况(可以合并 消除多份副本):
- 在a 带有a的函数中的return语句 类返回类型,表达式时 是非易失性的名称 与自动对象相同 cv-unqualified type作为函数 返回类型,复制操作即可 通过构造自动化省略 对象直接进入函数的 返回值
- 临时上课时 没有绑定到的对象 引用(12.2)将被复制到a 类对象与之相同 cv-unqualified类型,副本 操作可以省略 构造临时对象 直接进入了目标 省略副本
另请参阅“返回值优化”。