explorer

万丈高楼平地起,勿在浮沙筑高台

0%

Effective C++ :delete 优于私有未定义行为

如果不想让用户使用某个函数,那么有以下 3 种做法: 1. 使用delete限定 2. 将该函数设定为私有 3. 直接不定义该函数

最为合适的做法,就是使用delete限定。

3 种方法的差别

如果一个函数完成度不够或在实际行为上不允许用户调用该函数,那么:

直接将该函数屏蔽或删除

对于自己定义的函数,屏蔽它是一个做法,但这样总是看起来不优雅。

对于拷贝构造,拷贝赋值这类函数,如果不定义编译器也会有个默认版本,是无法将其直接删除的。

将该函数设定为私有

私有成员不能被用户调用,但是可以被friend或其它成员函数无意调用,这会造成逻辑漏洞。 > 当然可以只在类中声明它们,而不定义。这样在其被调用到时,编译器就会报错。但这报错并不能直接体现出类设计者的意图。

使用delete限定

使用delete是作为稳妥的办法,因为这是由编译器帮你把各个环节都限定了该函数不能被访问。

delete函数需要被设定为public访问权限

用户在访问一个方法的时候,编译器首先是检查其访问权限,然后才是检查其相关限定。

如果将一个delete函数放在private区,那么当用户访问的时候,就只会出现访问权限错误的警告。

而如果将一个delete函数放在public区,那么编译器就会给出正确的提示警告。

使用delete限定参数类型

1
2
3
4
5
bool isLucky(int number);            // original function
bool isLucky(char) = delete; // reject chars
bool isLucky(bool) = delete; // reject bools
bool isLucky(double) = delete; // reject doubles and
// floats

以上就限定了isLucky的输入参数必须是int类型。

对于模板函数,也可以对特点类型进行限定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename T>
void processPointer(T* ptr);
//限制 void* 偏特化
template<>
void processPointer<void>(void*) = delete;
template<>
void processPointer<const void>(const void*) = delete;
template<>
void processPointer<const void>(const volatile void*) = delete;
//限制 char* 偏特化
template<>
void processPointer<char>(char*) = delete;
template<>
void processPointer<const char>(const char*) = delete;
template<>
void processPointer<const char>(const volatile char*) = delete;

在类中的函数模板,也可以如此使用:

1
2
3
4
5
6
7
8
9
10
11
12
class Widget {
public:

template<typename T>
void processPointer(T* ptr)
{ … }

};
template<> // still
void Widget::processPointer<void>(void*) = delete; // public,
// but
// deleted