构造函数访问规则

时间:2009-05-19 10:28:10

标签: c++ constructor

如果我编译(在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);
}

2 个答案:

答案 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类型,副本   操作可以省略   构造临时对象   直接进入了目标   省略副本

另请参阅“返回值优化”。