Item 11: Prefer deleted functions to private undefined ones.

Item 11: Prefer deleted functions to private undefined ones.,第1张

Item 11: Prefer deleted funclass="superseo">ctions to private undefined ones. C++98 的做法C++11 的做法delete 函数优势

Effective Modern C++ Item 11 的学习和解读。

如果你的代码里有一些特殊的函数不想被别人调用,一般来说你不申明它即可。但是,有些特殊的成员函数,C++ 会自动申明,比如拷贝构造函数、拷贝赋值 *** 作。

C++98 的做法

C++98 的做法是将它们申明为私有并且不定义它们。以 IO 流为例,IO 流的基础类是 basic_ios,输入输出流都是继承与它。IO 流的拷贝是被阻止的(例如输入流 istream对象,表示输入数值,一些可能已经读入到内存中,一些可能还未读入,如果要复制一个输入流,是复制哪一部分?为了避免这样的问题,直接阻止 IO 流的拷贝)。

为了阻止 IO 流的复制,C++98 处理如下:

template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
...
private:
  basic_ios(const basic_ios& ); // not defined
  basic_ios& operator=(const basic_ios&); // not defined
};

将这些函数申明为私有并不定义,若这些函数被调用,在链接阶段将会因为没有定义而失败。

C++11 的做法

C++11 中有更好的处理方法,给这些函数标记为 “= delete” ,表明它们是被删除的函数:

template <class charT, class traits = char_traits<charT> >
class basic_ios : public ios_base {
public:
  ...
  basic_ios(const basic_ios& ) = delete;
  basic_ios& operator=(const basic_ios&) = delete;
  ...
};

删除函数不可以任何方式使用,即使是成员函数和友元函数。使用这些函数将导致编译报错。这比 C++98 中的方法诊断出错误的时间提前到编译阶段。

将 delete 函数申明为 public 的原因是:C++ 先检查访问权限,再检查 delete 状态。如果申明为 private,当使用删除的私有函数时,有些编译器只会报出这些函数是私有的,但其实更明确的含义是这些是删除函数,不期望被使用。

delete 函数优势

delete 函数的优势是它可以应用于任何函数,而不仅仅是成员函数。例如你有一个函数,只接受输入为 int 类型:

bool isLucky(int number);

但是,C++ 中很多类型都可以隐式转换为 int 类型。如下调用都可以通过:

isLucky('a');
isLucky(true);
isLucky(3.5);

C++11 的处理方法是将他们标记成 delete:

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

上面将参数为 double 的函数标记成 delete,可以阻止 float 和 double 两种参数的调用:C++总是倾向于将 float 转换为 double。

delete 函数的另一个优势体现在使用模板时候。如下面例子:

template<typename T>
void processPointer(T* ptr);

假设你想阻止 void* 和 char* 类型的特例,将这些函数的实例化标记成 delete 即可:

template<>
void processPointer<void>(void*) = delete;
template<>
void processPointer<const void>(const void*) = delete;
template<>
void processPointer<char>(char*) = delete;
template<>
void processPointer<const char>(const char*) = delete;

如果你在一个类内部有一个函数模板,你想通过声明它们为私有来禁止某些实现,是行不通的:因为模板的特例化无法在类的作用域内定义:

#include 

class A {
public:
  A();
  template<typename T>
  void processPointer(T* ptr) {
    std::cout << ptr << std::endl;
  }
private:
  template<>
  void processPointer<void>(void*);
};

int main()
{
    return 0;
}

// 报错信息:
main.cpp:12:12: error: explicit specialization in non-namespace scope 'class A'
   12 |   template<>
      |            ^
main.cpp:13:8: error: template-id 'processPointer' in declaration of primary template
   13 |   void processPointer<void>(void*);
      |  

使用 public 和 delete 方式则没有问题:

class A {
public:
  A();
  template<typename T>
  void processPointer(T* ptr) {
    std::cout << ptr << std::endl;
  }
};

template<>
void A::processPointer<void>(void*) = delete;

因此,选择使用 delete 函数吧。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/993545.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存