为什么auto_ptr似乎违反了Visual C ++的私人继承? [英] Why auto_ptr seems to breach private inheritance on Visual C++?
问题描述
背景信息:这是在Visual Studio 2008上检测到的,并在Visual Studio 2013上再次确认。G ++尖叫的代码,而Visual接受私人继承违约。
因此,在Visual C ++上,我们有以下代码:
class Base {};
class Derived:Base {}; //私下继承。明确添加
//关键字private更改没有
int main()
{
std :: auto_ptr< Base>(new Derived); // compiles,which is not EXPECTED
std :: auto_ptr< Base> p(new Derived); //不编译,这是预期的
}
auto_ptr compile?我在调试里面,它确实是一个公共继承(调用正确的构造函数等)。
想知道如果问题是使用auto_ptr实现(我们从不知道...),我减少了这个独立代码的问题:
class Base {} ;
class Derived:Base {};
template< typename T>
class Ptr
{
T * m_p;
public:
Ptr(T * p_p)
:m_p(p_p)
{
}
}
int main()
{
Ptr< Base>(new Derived); // compiles,which is not EXPECTED
Ptr< Base> p(new Derived); //不编译,这是预期的
}
不会编译,因为Derived继承自Base。
但是当我们创建一个临时,它的工作原理。
我们不能怪std :: auto_ptr。
我错过了标准(98或11或14)这是一个错误?
Derived *
to - Base *
转换,即使继承是私有的,也允许在C风格和函数转换。不,这不意味着 reinterpret_cast
在这种情况下。
这是标准不允许的,
5.2 .3显式类型转换(函数符号)[expr.type.conv]
1 [...]如果表达式列表是单个表达式,类型转换表达式与相应的强制转换表达式(5.4)是等效的(在定义中,如果在含义中定义)。 [...]
5.4显式类型转换(cast符号)[expr.cast] $ b
4由
执行的转换- a
const_cast
11),
- a
static_cast
(5.2.9),
- a
static_cast
后跟一个const_cast
,
- a
reinterpret_cast
(5.2.10)或
- a
reinterpret_cast
code>,
可以使用显式类型转换的转换符号执行。相同的语义限制和行为适用,除了在以下情况下执行
static_cast
时,即使基类不可访问,转换也是有效的: / p>
- 指向导出类类型的对象的指针或派生类类型的左值或右值可以被显式地
转换为指针
$ b $ b
在这种情况下,编译器将其解释为 static_cast
从 Derived *
到 auto_ptr< Base>
,并且在 static_cast
到无歧义基类类型的指针。
但是,从 Derived *
到 Base *
是隐式的,它只是作为显式不同转换的一部分而被执行。所以最后,不,标准真的不允许它。
您可能想报告为一个错误。从 Csq 的评论,我们了解到有一个相关报告,其中显式 static_cast
也允许这种转换,但它不完全相同的事情。在这种情况下,从 Derived *
到 Base *
的转换是显式的,但在这里是隐式的,Visual C ++
请注意,在使用多个表达式的函数转换中,这种误解是不可能的:编译器正确地拒绝以下内容:
class Base {};
class Derived:Base {};
template< typename T>
class Ptr {
public:
Ptr(T * a,T * b){}
};
int main(){
Ptr< Base>(new Derived,new Derived);
//错误C2243:'type cast':存在从'Derived *'到'Base *'的转换,但不可访问
}
Background information: This was detected on Visual Studio 2008, and confirmed again on Visual Studio 2013. G++ screamed at the code, while Visual accepted the private inheritance breach silently.
So, on Visual C++, we have the following code:
class Base {};
class Derived : Base {}; // inherits privately. Adding explicitly the
// keyword private changes nothing
int main()
{
std::auto_ptr<Base>(new Derived) ; // compiles, which is NOT EXPECTED
std::auto_ptr<Base> p(new Derived) ; // Does not compile, which is expected
}
Why would the first (temporary) auto_ptr compile? I went inside it in debug, it did exactly what is was supposed to do with a public inheritance (call the right constructor, etc.)
Wondering if perhaps the issue was with the auto_ptr implementation (we never know...), I reduced the issue on this standalone code:
class Base {};
class Derived : Base {};
template <typename T>
class Ptr
{
T * m_p;
public :
Ptr(T * p_p)
: m_p(p_p)
{
}
} ;
int main()
{
Ptr<Base>(new Derived) ; // compiles, which is NOT EXPECTED
Ptr<Base> p(new Derived) ; // Does not compile, which is expected
}
Again, I expected the code to NOT compile, as Derived inherits privately from Base.
But when we create a temporary, it works.
And we can't blame it on std::auto_ptr.
Is there something in the standard (either 98 or 11 or 14) I missed, or is this a bug?
The Derived*
-to-Base*
conversion, even if the inheritance is private, is permitted in C-style and functional casts. And no, it doesn't mean reinterpret_cast
in that case.
This isn't allowed by the standard, but it very nearly looks as if it is allowed, so it's a subtle bug.
5.2.3 Explicit type conversion (functional notation) [expr.type.conv]
1 [...] If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4). [...]
5.4 Explicit type conversion (cast notation) [expr.cast]
4 The conversions performed by
- a
const_cast
(5.2.11),- a
static_cast
(5.2.9),- a
static_cast
followed by aconst_cast
,- a
reinterpret_cast
(5.2.10), or- a
reinterpret_cast
followed by aconst_cast
,can be performed using the cast notation of explicit type conversion. The same semantic restrictions and behaviors apply, with the exception that in performing a
static_cast
in the following situations the conversion is valid even if the base class is inaccessible:
- a pointer to an object of derived class type or an lvalue or rvalue of derived class type may be explicitly converted to a pointer or reference to an unambiguous base class type, respectively;
- [...]
In the situation you've got, the compiler interprets it as a static_cast
from Derived*
to auto_ptr<Base>
, and in that static_cast
, a pointer to an object of derived class type is converted to a pointer of an unambiguous base class type. So it looks like the standard allows it.
However, the conversion from Derived*
to Base*
is implicit, it merely happens to be performed as part of an explicit different conversion. So in the end, no, the standard really doesn't allow it.
You may want to report this as a bug. From Csq's comment, we learn that there is a related report, in which an explicit static_cast
also allows this conversion, but it's not exactly the same thing. In that case, the conversion from Derived*
to Base*
is explicit, but it is implicit here, and Visual C++ does usually reject that in implicit conversions.
Note that in functional casts that use multiple expressions, this misinterpretation isn't possible: the compiler correctly rejects the following:
class Base { };
class Derived : Base { };
template <typename T>
class Ptr {
public:
Ptr(T *a, T *b) { }
};
int main() {
Ptr<Base>(new Derived, new Derived);
// error C2243: 'type cast' : conversion from 'Derived *' to 'Base *' exists, but is inaccessible
}
这篇关于为什么auto_ptr似乎违反了Visual C ++的私人继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!