【Effective Modern C++】第三章 转向现代C++:11. 优先选用删除函数,而非private未定义函数

主要考虑复制构造函数和复制赋值运算符:C++ 会自动生成这类特殊成员函数,但部分场景(如iostreambasic_ios类)中拷贝操作存在逻辑歧义(如流的读取状态、资源句柄拷贝混乱),因此需要主动禁止这些函数被调用。

C++98 禁止函数调用的方案:私有声明 + 未定义

为阻止复制构造 / 赋值运算符被使用,C++98 采取 "声明为 private + 不定义" 的方式:

c++ 复制代码
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
};
  • 作用逻辑:private修饰阻止客户端代码调用;故意不定义函数,若成员 / 友元函数误调用,会在链接期触发 "缺少函数定义" 错误。
  • 缺陷:报错时机晚,仅链接期提示错误,排查成本高。

C++11 更优方案:deleted 函数(= delete)

C++11 通过= delete标记函数为 deleted,实现禁止调用的目的:

c++ 复制代码
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;
	...
};

deleted 函数的基础优势(对比 C++98)

  1. 调用限制更严格:deleted 函数无法以任何形式被调用(包括成员 / 友元函数调用),且编译期直接报错,报错时机更早、排查更易;
  2. 错误提示更精准:deleted 函数建议声明为public(C++ 先检查访问性,再检查 deleted 状态),编译器会直接提示 "函数已被删除",而非仅提示 "private"。

deleted 函数的扩展优势(C++98 方案无法实现)

private仅能作用于类成员函数,而任何函数都可标记为 deleted,典型场景如下:

  1. 禁止非成员函数的不合理隐式调用:

过滤非目标类型的隐式转换调用(如仅允许 int 类型调用isLucky,禁止 char/bool/double):

c++ 复制代码
bool isLucky(int number);
bool isLucky(char) = delete;    // 拒绝char类型
bool isLucky(bool) = delete;    // 拒绝bool类型
bool isLucky(double) = delete;  // 拒绝float/double类型
  1. 禁止模板的特定实例化:

拒绝模板针对void*/char*等特殊类型的实例化:

c++ 复制代码
template<typename T>
void processPointer(T* ptr);

// 禁止void*和char*实例化
template<>
void processPointer<void>(void*) = delete;
template<>
void processPointer<char>(char*) = delete;

若需彻底禁止,还需删除const void*const volatile void*const char*const volatile char*重载版本,以及std::wchar_tstd::char16_tstd::char32_t等字符类型的重载版本。

补充:private 无法实现类内模板函数的特定实例化禁止

模板特例化必须位于命名空间作用域,而非类作用域,因此在类内用private声明模板特化版本会直接编译错误;而 deleted 函数可在类外(命名空间作用域)删除类内模板的特化版本,无此限制:

c++ 复制代码
class Widget {
public:
    template<typename T>
    void processPointer(T* ptr) { /* ... */ }
};
// 类外删除void*版本的特化,编译通过且实现禁止调用
template<>
void Widget::processPointer<void>(void*) = delete;

总结

  • 优先选用删除函数,而非private函数
  • 任何函数都可以删除,包括非成员函数和模板具现。

原著在线阅读地址

相关推荐
库玛西2 小时前
深入浅出传输层:UDP 与 TCP 协议全景指南
linux·服务器·网络·c++·笔记·tcp/ip·udp
Chester_19998 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
会周易的程序员9 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
小灰灰搞电子10 小时前
完全驾驭 Qt 与数据库:C++ ORM 框架 QxOrm 原理与实践指南
数据库·c++·qt
QT界面美化性能优化10 小时前
QT+AI:使用AI技术为QT应用程序赋能
c++·人工智能·qt·opencv·qt教程·qt6.3
学习星球12 小时前
单调栈——从“找下一个更大的“到柱状图中的最大矩形
数据库·c++·算法·leetcode·xcode
小灰灰搞电子13 小时前
C++ 引用折叠详解
c++
布莱克60513 小时前
数组详解:定义、作用、应用场景及与链表的区别(C/C++ 代码讲解)
c语言·开发语言·c++·数组
牛油果子哥q14 小时前
C++内存池与对象池精讲:内存碎片、自定义分配器、对象池实现、STL allocator原理、工程落地与性能对比
java·开发语言·c++
万法若空15 小时前
C/C++ 类型别名定义方式对比
java·c语言·c++