当私有拷贝构造函数带有公共赋值运算符时出错
你们中有人能解释一下为什么下面的代码不能编译吗?
#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
注意:当我删除 private: 关键字时,代码会编译,但永远不会调用复制构造函数。那么为什么当它是私有的时会出错呢?
不确定它是否重要,但我正在使用:
$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
Can one of you explain why the following piece of code does not compile?
#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();
}
The error I receive:
$ 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
Note: when I remove the private: keyword the code compiles but the copy ctor is never called. So why does it err when it's private?
Not sure if it's important but I'm using:
$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您正在初始化临时引用。
标准规定:
应“使用非引用复制初始化规则 (8.5)”来初始化临时对象(8.5.3 第 5 部分)。
临时删除复制结构(标准允许。12.8 par 5)。
然而,该标准明确规定(12.2 par 1):
“即使避免创建临时对象(12.8),也必须遵守所有语义限制,就像创建临时对象一样。[示例:即使不调用复制构造函数,所有语义限制,例如可访问性(第 11 条),应满足。]”
(另外,在寻找正确的引用时,发现了这个 重复 :)
编辑:
从标准中添加相关位置
You are initializing a reference from temporary.
The standard states:
The temporary should be initialized (8.5.3 par 5)"using the rules for a non-reference copy initialization (8.5)".
The copy construction is removed for the temporary (permitted by the standard. 12.8 par 5).
However, the standard clearly states (12.2 par 1):
"Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created. [Example: even if the copy constructor is not called, all the semantic restrictions, such as accessibility (clause 11), shall be satisfied. ]"
(also, when looking for the right quote, found this duplicate :)
Edit:
adding relevant location from the standard
该代码使用 gcc 4.3.3 和 4.4.1 进行编译。也许这只是 gcc 4.1 中的一个错误?
That code compiles with gcc 4.3.3 and 4.4.1. Maybe that's just a bug in gcc 4.1?
假设您发布的代码是项目中的唯一代码,并且在任何地方都没有按值秘密传递 Foos,我所能想到的是 gcc 正在优化
......
这是不健全的,作为第一种形式是一个默认构造和一个赋值,而第二个相当于
......这显然是一个复制构造。如果我是对的,复制构造函数不会运行,因为 GCC 可以优化掉多余的临时文件;这是 C++ 规范允许的。
一般来说,将赋值运算符和复制构造函数置于不同的保护级别并不是一个好主意;正如您所看到的,结果可能并不直观。
Assuming that the code you've posted is the only code in the project, and there's no covert passing of Foos by value going on anywhere, all I can figure is that gcc is optimizing
to
...which is unsound, as the first form is a default-construct and an assignment, while the second is equivalent to
...which is clearly a copy construction. If I'm right, the copy constructor is not being run because GCC can optimize away the redundant temporary; this is permitted by the C++ spec.
In general, it is not a good idea to have assignment operators and copy constructors at different protection levels; as you've seen, the results can be unintuitive.
Copy Ctor 在以下情况下被调用:
因此,您肯定会在代码中的某处执行其中一种或两种情况。您应该将 Copy Ctor 设置为公共或避免前面的 2 种情况。
Copy Ctor is called when:
So you are certainly doing one or both of these case somewhere in your code. You should set Copy Ctor as public or avoid the 2 previous cases.
如果您编写,将调用复制构造函数
在您的情况下,首先调用默认构造函数,然后调用operator=方法。
Copy constructor would be called if you write
In your case, first the default constructor is called and then the operator= method.
在
Foo f2=f1;
中检查这一点(f2
是使用复制构造函数创建的)Check this, in
Foo f2=f1;
(f2
is created using copy constructor)