2009-10-13 100 views
6

您可以解释为什么以下代码不能编译?与公共分配操作员私人复制ctor时出错

#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() { cout << "Foo::Foo()" << endl << endl; } 
    Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; } 
private: 
    Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; } 
}; 

int main() 
{ 
    Foo foo; 

    foo = Foo(); 
} 

错误我收到:

$ g++ -o copy_ctor_assign copy_ctor_assign.cc && ./copy_ctor_assign 
copy_ctor_assign.cc: In function 'int main()': 
copy_ctor_assign.cc:10: error: 'Foo::Foo(const Foo&)' is private 
copy_ctor_assign.cc:17: error: within this context 

注:当我删除私人:关键字代码编译,但拷贝构造函数永远不会被调用。那么为什么它在私密时会犯错?

不知道,如果是重要的,但我使用:

$ g++ --version 
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44) 
Copyright (C) 2006 Free Software Foundation, Inc. 
+1

FWIW:代码确实co如果分配一个先前创建的Foo对象而不是临时对象,则为mpile。即'foo = bar;'而不是'foo = Foo();'。 – sepp2k 2009-10-13 15:47:35

回答

5

要初始化从临时参考(f2使用拷贝构造函数创建)。
标准状态:
使用非参考副本初始化(8.5)的规则,临时值应该初始化(8.5.3参数5)“。

临时删除复制结构(由标准允许的12.8部分5)。
然而,标准明确规定(12.2帕1):
“即使避免了临时对象的创建(12.8),因为如果临时对象的创建的所有语义限制必须遵守[实施例:偶如果拷贝构造函数不叫,所有的语义限制,如可访问性(第11条),应满足]”

(也,寻找合适的报价的时候,发现这个duplicate :)

编辑: 从标准添加相关位置

+0

这个答案是正确的,但是你引用了'8.5.3第5段'的错误部分(在我们的例子中,我们有类类型和引用兼容类型,所以应该采用* previous *项目符号)。重要的是前一个,它表示是否复制是实现定义的,然后“无论副本是否实际完成,用于制作副本的构造函数都可以调用”。对于C++ 0x,该实现不允许复制,并且不再需要复制构造函数。 – 2009-10-13 21:43:13

+0

我纠正:) 谢谢 – 2009-10-13 23:03:05

+0

谢谢你,今天我学到了一些新东西。 – sdumi 2009-10-14 06:53:12

1

拷贝构造函数被调用时:

  1. 按值传递的对象作为参数传递给函数,
  2. 返回一个对象来自一个函数。

因此,您当然在代码中的某个位置执行一个或两个这种情况。您应该将Copy Ctor设置为公开或避免之前的两个案例。如果你写

Foo foo; // normal constructor 
Foo foo1(foo); //copy constructor 

在你的情况

+0

他做到了。 尝试编译他的代码。错误提出(没有任何额外的代码) – 2009-10-13 16:15:35

0

复制构造函数被调用,第一个默认的构造函数被调用,那么运营商=方法。

+0

那么为什么他的代码不能编译? – sepp2k 2009-10-13 15:43:44

+0

也许他的代码不能与Werror编译? ;) – UncleBens 2009-10-13 15:52:51

3

假定您已经发布的代码是在项目中唯一的代码,并有FOOS没有秘密路过的价值去任何地方,所有我可以计算是GCC是优化

Foo foo; 
foo = Foo(); 

Foo foo = Foo(); 

...这是不健全,作为第一形式是一个默认的构建体和一个赋值,而第二个是相当于

Foo foo(Foo()); 

......这显然是一个复制结构。如果我是对的,复制构造函数不会运行,因为GCC可以优化多余的临时;这是C++规范允许的。

通常,在不同的保护级别使用赋值操作符和拷贝构造函数并不是一个好主意;正如你所见,结果可能不直观。

+0

gcc无法优化这样的构造函数,因为它们有副作用('cout's)。如果gcc这样做,这是一个错误。 – CAdaker 2009-10-13 15:50:27

+0

@CAdaker:不可以。删除多余的临时对象是一种特殊情况,C++标准明确允许在这种情况下删除复制构造。 – 2009-10-13 15:52:41

+0

即使临时对象具有非平凡的构造函数和析构函数?这听起来完全疯了。 – CAdaker 2009-10-13 15:57:29

4

该代码用gcc 4.3.3和4.4.1编译。也许这只是gcc 4.1中的一个错误?

+0

你可以尝试使用-Wall在这些版本中重新编译吗? 谢谢 – 2009-10-13 16:47:22

+0

我得到关于operator =的警告=没有返回一个值,但其他都没有。 – CAdaker 2009-10-13 16:54:07

+0

它对我来说是失败的:使用g ++(GCC)3.4.4 – 2009-10-13 18:54:31

-1
#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() { cout << "Foo::Foo()" << endl << endl; } 
    Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; } 
    Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; } 
}; 

int main() 
{ 
    Foo f1;// default constructor called 

    Foo f2 = f1; //copy constructor called 
} 

入住这一点,在Foo f2=f1;

+0

你想在上面的代码中说什么?这个问题被问到为什么当复制构造函数是私有时它会得到编译错误。你只是举了一个默认构造函数和复制构造函数的例子。 – Jagannath 2009-10-13 16:01:43