【发布时间】:2012-01-19 04:34:59
【问题描述】:
我有以下代码(仅适用于 gcc):
#include <iostream>
#include <cstdlib>
#include <string>
#include <typeinfo>
#include <cxxabi.h>
const std::string demangle (const char* name) {
int status = -4;
char* res = abi::__cxa_demangle(name, 0, 0, &status);
const char* const demangled_name = (status == 0) ? res : name;
std::string ret_val(demangled_name);
std::free(res);
return ret_val;
}
template <typename T>
const std::string getname (T x)
{
return demangle(typeid(x).name());
}
int main()
{
std::add_const<int>::type *p = static_cast<const int *>(0);
std::cout << getname(*p) << std::endl;
}
在我的本地计算机上(使用 gcc 4.7.0(实验)它崩溃了(使用 gdb 运行会产生段错误)。但是,使用 ideone.com,它会按预期打印“int”。继承人,a link to the example。另外,去掉模板直接调用demangle(typeid(x).name())就解决了,那么模板有什么问题呢?
编辑
我忘了包含解决问题的 type_traits 标头(doh!),但是我仍然想知道发生了什么更好。
【问题讨论】:
-
嗯,显而易见的答案是您正在取消引用一个空指针,即 UB,因此您观察到的两个结果都是“正确的”。
-
@todda.speot.is:按照标准的规定,它在 C++ 中是未定义的行为。如果您想在特定时间谈论特定硬件上特定平台上的特定 C++ 实现,那很好,但要意识到您不再谈论 C++ 语言。
-
@GMan 诚然,在 C++ 标准中涉及 NULL 指针的某些操作存在未定义的行为,所以我收回我的 cmets。然而open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 似乎认为它在某些情况下定义了行为,并且在阅读了更多之后似乎在这种情况下它是定义行为Objects of class
std::bad_typeidare thrown whentypeidis called on a dereferenced null pointer。虽然它对于其他操作是未定义的。 -
@todda.speot.is:请注意,问题仍然存在,AFAIK 未纳入新标准。 (This was an area of interest to me.) 反正那篇文章里的那句话其实太丢人了,标准中的相关章节是§5.2.8/2。它非常明确地表示,
typeid表达式中的表达式 可以采用*p、*(p)等形式,而p可以为空。这里不是这种情况,UB 已经发生了。 -
@GMan 你说得对,
*p不是typeid的表达式。
标签: c++ gcc c++11 segmentation-fault