刚刚发现了一个阴险的崩溃的原因是一个未检查的野生由编译器,而不考虑类型。这是预期的行为还是编译器的错误?
Problem:当涉及类型定义时,可以进行隐式重新解释cast,从而破坏类型系统。
#include <iostream>
template<class A, class B>
inline bool
isSameObject (A const& a, B const& b)
{
return static_cast<const void*> (&a)
== static_cast<const void*> (&b);
}
class Wau
{
int i = -1;
};
class Miau
{
public:
uint u = 1;
};
int
main (int, char**)
{
Wau wau;
using ID = Miau &;
ID wuff = ID(wau); // <<---disaster
std::cout << "Miau=" << wuff.u
<< " ref to same object: " <<std::boolalpha<< isSameObject (wau, wuff)
<< std::endl;
return 0;
}我震惊地发现gcc-4.9、gcc-6.3和clang-3.8接受了这段代码,没有任何错误,并产生了以下输出:
Miau=4294967295 ref to same object: true请注意,我使用了类型构造函数语法ID(wau)。我预计这种行为在C型演员身上,即(ID)wau上。只有当使用新的花括号语法ID{wau}时,我们才会得到预期的错误.
~$ g++ -std=c++11 -o aua woot.cpp
woot.cpp: In function ‘int main(int, char**)’:
woot.cpp:31:21: error: no matching function for call to ‘Miau::Miau(<brace-enclosed initializer list>)’
ID wuff = ID{wau};
^
woot.cpp:10:7: note: candidate: constexpr Miau::Miau()
class Miau
^~~~
woot.cpp:10:7: note: candidate expects 0 arguments, 1 provided
woot.cpp:10:7: note: candidate: constexpr Miau::Miau(const Miau&)
woot.cpp:10:7: note: no known conversion for argument 1 from ‘Wau’ to ‘const Miau&’
woot.cpp:10:7: note: candidate: constexpr Miau::Miau(Miau&&)
woot.cpp:10:7: note: no known conversion for argument 1 from ‘Wau’ to ‘Miau&&’不幸的是,由于std::initializer_list的失败,大括号的语法常常是模板繁重的代码中不能使用的。所以对我来说,这是一个严重的问题,因为类型系统的保护实际上在这里崩溃了。
发布于 2018-10-12 16:04:54
可以进行隐式重解释,从而破坏类型系统。 ID wuff = ID(wau);
这不是“含蓄”的重释演员。这是显式类型转换。尽管如此,转换确实不容易被重新解释。具体来说,转换的语法称为“功能样式”。
如果您不确定显式类型转换的类型(是使用函数语法,还是使用C样式语法),那么应该避免使用它。许多人会争辩说,不应该使用显式类型转换。
如果您使用的是static_cast,那么您将一直处于类型系统的保护范围内:
ID wuff = static_cast<ID>(wau);
error: non-const lvalue reference to type 'Miau' cannot bind to a value of unrelated type 'Wau'简单地依赖隐式转换通常也是安全的:
ID wuff = wau;
error: non-const lvalue reference to type 'Miau' cannot bind to a value of unrelated type 'Wau'这是故意的行为吗
是。
还是编译器的错误?
不是的。
https://stackoverflow.com/questions/52782967
复制相似问题