意外的 const 引用行为
#include <iostream>
class A {
public:
A(){ cerr << "A Constructor" << endl; }
~A(){ cerr << "A Destructor" << endl; }
A(const A &o){ cerr << "A Copy" << endl; }
A& operator=(const A &o){ cerr << "A Assignment" << endl; return *this; }
};
class B : public A {
public:
B() : A() { cerr << "B Constructor" << endl; }
~B(){ cerr << "B Destructor" << endl; }
private:
B(const B &o) : A() { cerr << "B Copy" << endl; }
B& operator=(const B &o){ cerr << "B Assignment" << endl; return *this; }
};
int main() {
A a;
const A &b = B();
return 0;
}
在 GCC 4.2 中,我收到此消息:
In function 'int main()':
Line 16: error: 'B::B(const B&)' is private
compilation terminated due to -Wfatal-errors.
如果我从 B 中删除“private”,我会得到我期望的输出:
A Constructor
A Constructor
B Constructor
B Destructor
A Destructor
A Destructor
我的问题是:为什么创建一个不称为 private 的方法会更改此代码是否可以编译?这是标准规定的吗?有解决方法吗?
#include <iostream>
class A {
public:
A(){ cerr << "A Constructor" << endl; }
~A(){ cerr << "A Destructor" << endl; }
A(const A &o){ cerr << "A Copy" << endl; }
A& operator=(const A &o){ cerr << "A Assignment" << endl; return *this; }
};
class B : public A {
public:
B() : A() { cerr << "B Constructor" << endl; }
~B(){ cerr << "B Destructor" << endl; }
private:
B(const B &o) : A() { cerr << "B Copy" << endl; }
B& operator=(const B &o){ cerr << "B Assignment" << endl; return *this; }
};
int main() {
A a;
const A &b = B();
return 0;
}
In GCC 4.2, I get this message:
In function 'int main()':
Line 16: error: 'B::B(const B&)' is private
compilation terminated due to -Wfatal-errors.
If I remove the "private" from B, I get the output I expect:
A Constructor
A Constructor
B Constructor
B Destructor
A Destructor
A Destructor
My question is: why does making a method which isn't called private change whether this code compiles? Is this standard-mandated? Is there a workaround?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当前标准 (C++03) 中的重要措辞似乎在 §8.5.3 中,它解释了如何初始化引用(在这些引号中,
T1
是正在初始化的引用的类型,T2
是初始化表达式的类型)。因此,即使实现将引用直接绑定到临时对象,复制构造函数也必须可访问。
请注意,根据 CWG 缺陷 391。新语言如下(N3092 §8.5.3):
适用第一种情况,并且引用“直接绑定”到初始值设定项表达式。
The important verbiage in the current standard (C++03) seems to be in §8.5.3, which explains how references are initialized (In these quotes,
T1
is the type of the reference being initialized andT2
is the type of the initializer expression).So, even if the implementation binds the reference directly to the temporary object, the copy constructor must be accessible.
Note that this is changed in C++0x, per the resolution of CWG defect 391. The new language reads (N3092 §8.5.3):
The first case applies and the reference is "bound directly" to the initializer expression.
所以你使用的是“复制初始化”:
,所选构造函数的重载为:
因此,对于复制初始化,复制构造函数必须可用。但是,编译器可以“优化”副本:
12.2/1 临时对象
您可以通过避免复制初始化并使用直接初始化来获得您想要的效果:
注意:
由于较新版本的 GCC 显然有不同的行为,我想我应该发布此注释,这可能会解决差异(两种行为仍然符合标准):
8.5.3/5 参考文献说:
我最初阅读了最后一句(“将使用的构造函数...”)以应用于这两个选项,但也许它应该被理解为仅应用于秒选项 - 或者至少也许这就是 GCC 维护者正在阅读的方式它。
我不确定这是否是 GCC 版本的不同行为之间发生的情况(欢迎评论)。我们肯定已经达到了我的语言律师技能的极限......
So what you're using is 'copy-initialization':
In 13.3.1.3 "Initialization by constructor", the overloads for the constructor chosen are:
So, for copy-initialization, the copy constructor must be available. However, the compiler is permitted to 'optimize away' the copy:
12.2/1 Temporary objects
You can get the effect you want by avoiding copy-initialization and using direct-initialization:
Note:
Since newer versions of GCC apparently have a different behavior, I thought I'd post this note, which might address the difference (with both behaviors still standards conforming):
8.5.3/5 References says:
I originally read the last sentence ("the constructor that would be used...") to apply to both options, but maybe it should be read as only applying to the seconds option - or at least maybe that's how the GCC maintainers are reading it.
I'm not sure if this is what's going on between the differing behavior of GCC versions (comments welcome). We're definitely reaching the limits of my language-lawyering skills...
我认为这确实是一个编译器错误,gcc似乎认为这是复制初始化。请改用直接初始化:
复制初始化中的复制构造函数调用始终会被优化掉(复制省略的实例),因此不必可用。
I think it is indeed a compiler bug, gcc seems to think that is is copy initialization. Use direct initialization instead:
The copy-constructor call in copy initialization is always optimized away (an instance of copy elision), and then doesn't have to be available.