引子
这一条目就比较简单了,就是宣传用nullptr
来指代空指针,而不是之前的0
或者NULL
。
正文
在老式C++中,显然0
是int
类型,而NULL
也是一个整数类型(int
或者long
)。总的来说,这两个常用来表示空指针的符号并不是真正的指针类型。这样,当我们在进行函数重载时会发生麻烦,例如:
void f(int); // three overloads of f
void f(bool);
void f(void*);
f(0); // calls f(int), not f(void*)
f(NULL); // might not compile, but typically calls f(int). Never calls f(void*)
所以在C++98中,一些准则教育程序员不要同时重载int
和指针类型。但在C++11中,移除了这个限制,因为我们有一个新的关键字nullptr
来代表空指针。
但是,准确的说,nullptr
也不是空指针类型而是std::nullptr_t
类型。这里有点循环定义的意思在里面,因为std::nullptr_t
类型就是nullptr
的类型。
此时我们再调用f(nullptr)
时就准确地调用了f(void*)
而不是其他重载函数。因为nullptr
不会被转换为基本类型。
不过虽然0
可以被看作空指针,但是并不是int
类型会被隐式转换为空指针,例如:
void test(void*);
int data = 0;
test(0); //Ok, but not recommanded
test(data); //Error, could not convert from "int" to "void*"
了解了上面的机制,你就很容易看懂最后这个模板的例子:
using MuxGuard = std::lock_guard<std::mutex>;
template<typename FuncType,
typename MuxType,
typename PtrType>
decltype(auto) lockAndCall(FuncType func,
MuxType& mutex,
PtrType ptr
{
MuxGuard g(mutex);
return func(ptr);
}
int f1(std::shared_ptr<Widget> spw); // call these only when
double f2(std::unique_ptr<Widget> upw); // the appropriate
bool f3(Widget* pw); // mutex is loc
std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3
auto result1 = lockAndCall(f1, f1m, 0); // error!
auto result2 = lockAndCall(f2, f2m, NULL); // error!
auto result3 = lockAndCall(f3, f3m, nullptr); // fine
上面前两次调用都失败了,这是由于0
和NULL
都被推导为整数类型,并进一步传递个内部的函数func
(这里是f1
和f2
)。而整数类型无法被转换为指针类型,故代码错误。
总结
综上,我们有:
1.用
nullptr
代替0
和NULL
来指示空指针。
2.不要同时重载参数为整数类型和指针类型的函数。