【发布时间】:2013-05-11 13:15:00
【问题描述】:
我想检查 dynamic_cast 的结果。在 c++11(或 c++0x,对于支持 nullptr 的编译器)中,我应该与 nullptr 还是 0 进行比较?
重要吗?如果重要,为什么?
结果是否依赖于编译器?
【问题讨论】:
标签: c++11 dynamic-cast nullptr
我想检查 dynamic_cast 的结果。在 c++11(或 c++0x,对于支持 nullptr 的编译器)中,我应该与 nullptr 还是 0 进行比较?
重要吗?如果重要,为什么?
结果是否依赖于编译器?
【问题讨论】:
标签: c++11 dynamic-cast nullptr
常量nullptr(类型为nullptr_t)和常量0都将隐式转换为任何指针类型的空值。因此,与任何一个进行比较都可以,并且在技术上是可以的。顺便说一句,这意味着dynamic_cast 不返回任何一个,它返回特定指针类型的空值。
最好养成使用nullptr 而不是0 的习惯。据我所知,只有正确的重载解决方案才真正需要(例如,一个重载需要int,另一个需要char*)。为了保持一致性,最好避免使用0。
“指针类型的空值”是什么意思?
考虑一个变量char * ptr。它的类型是(不出所料)char *。但是nullptr 的类型是特殊类型nullptr_t。所以当我们写ptr = nullptr这样的东西时,一定会发生一些技术性的事情
nullptr 必须隐式转换为 char *。ptr 的新值。char * 的空值是将nullptr 转换为char * 的结果。从概念上讲,它仍然是 nullptr,但具有不同的类型 (char *)。此空值不同于 int * 或 string * 或任何其他指针类型的空值。我们倾向于将这些空值视为nullptr(或0),但每个值实际上都是来自不同类型的不同值。 (顺便说一下,使用== 进行比较时会发生相同的转换。
虽然这听起来像是挑剔的细节,但它在重载解决方案中非常重要:
void foo(char * ptr) { ... }
void foo(int i) { ... }
void foo(nullptr_t ptr) { ... }
int main()
{
foo(0); // Calls void foo(int), since 0 is an int
foo(nullptr); // Calls void foo(nullptr_t), since nullptr is a nullptr_t
foo(new char('c')); // Calls void foo(char *), since new char('c') is a char*
}
或在分配不相关的空值时:
char * c_ptr = nullptr; // Okay
int * i_ptr1 = nullptr; // Okay
int * i_ptr2 = c_ptr; // COMPILER ERROR HERE
【讨论】:
if (nullptr == dynamic_cast<foo*>(p))的时候,是不是先把nullptr转换成foo*的null值,然后再做比较呢?
0 和 nullptr 在转换为指针类型时必须比较等于指针类型的空值,并且如果您在 boolean 上下文中评估指针,则指针类型的空值必须评估为假,非空值为真。然而,大多数环境将空指针存储为一堆零位。 :)
在布尔上下文中评估结果:
Base * p = get();
if (Derived * q = dynamic_cast<Derived *>(p))
{
q->derived_method();
}
else
{
// *p isn't of type Derived
}
(这适用于任何版本的 C++。)
【讨论】:
nullptr 一直存在),因为它不仅仅适用于与nullptr 相比的类型。它适用于任何具有空虚概念的类型,表示为转换为bool,就像optional<T> 一样。我也认为像std::function 这样的类型看起来更好,它与nullptr 相当,但实际上不是指针类型!