c++11 中函数声明 新关键字 delete的妙用之一: 搭配宏NonCopyable(ClassName) 使用
来源:互联网 发布:迅捷数据恢复注册问题 编辑:程序博客网 时间:2024/06/05 22:47
c++11 中函数声明 新关键字 delete的妙用之一: 搭配宏NonCopyable(ClassName) 使用
编译器版本: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
1. 首先先来见识一下 c++11 声明中的新关键字 delete
使用如下代码先来试试水.
#include <string>class Person{public: Person(std::string name) : name_(name) { } Person(const Person &name) = delete;private: std::string name_;}; int main(int argc, char **argv){ Person p1("Crane"); Person p2(p1);}
首先, 这是一个Person类.借用莱布尼茨一句老掉牙的话: "世界上没有两片完全相同的叶子,也没有性格完全相同的人。"
体现在Person类中, 就是不允许任何两个用户的名字相同, 首先从根源上杜绝: 禁止Person类的拷贝构造函数和赋值运算符.
这里使用 C++11 成员函数声明新特性: = delete, 从逻辑语义上禁止了对于 Person类拷贝构造函数和赋值运算符,
使用g++ 命令编译
g++ -std=c++11 -g -Wall main.cpp -o main
编译错误如下: ( 记得开启 编译器 C++11 支持 )
main.cpp: In function ‘int main(int, char**)’:
main.cpp:37:17: error: use of deleted function ‘Person::Person(const Person&)’
Person p2(p1);
^
main.cpp:26:5: note: declared here
Person(const Person &) = delete;
编译器明确提示了 在main函数中, 使用了 deleted function. 并且给出了行号, 错误原因一目了然. 用户看到这样的错误信息, 很快可以定位到问题所在.
并且注意一点: " = delete " 函数声明和成员函数的作用域已经无关了, 既可以放在private域中, 也可以放在public 域中.
2. 在 delete没有出现之前的解决方案:
看完了“ = delete” 声明禁止某些函数使用的方式。 再来回想一下在没有 = delete 的年代里, 如何禁止类的拷贝构造函数和赋值运算符的使用。
简单来说, 就是将禁止使用的成员函数其声明为private类型: 将拷贝构造函数和赋值运算符放到private域中。
这样也是可以工作的,boost::noncopyable就是基于private 这样的方式干的。
3. 用宏来实现NonCopyable的功能: 通过private实现.
如果我有很多类,都禁止拷贝的情况下......使用private来实现noncopyable.
在我的项目中, 有很多资源管理类, 这些类都使用RAII的手法来管理资源. 这些类很多都是不可以拷贝构造的.
比如Scoped_Mutex, Scoped_Curson, Scoped....
于是乎, 代码如下:
class Scoped_Mutex{private: Scoped_Mutex(const Scoped_Mutex &) ; Scoped_Mutex & operator =(const Scoped_Mutex &) ;}; class Scoped_Cursor{private: Scoped_Cursor(const Scoped_Cursor &) ; Scoped_Cursor & operator =(const Scoped_Cursor &) ;};....
这样每个类中都要写这些倒人胃口的private 函数声明, 并且和程序逻辑没有半毛钱关系, 如果是这样, 或许为了偷懒, 我就不写了.
那么问题来了: 既然boost已经实现了 boost::noncopyable, 直接用自己的类继承 boost::noncopyable不就好了吗.
当然在对boost依赖较大时, 可以这样. 但是在我的源码中, 如果只是因为noncopyable, 就去使用boost. 真是划不来.
并且如果我的源码是用来提供基础库服务的. 这样每一个使用我的服务的上层应用, 都要强制安装boost. 用户会觉得: oh, shit !
所以如果没有足够的对于boost的需求积累, 在代码里就不会轻易使用boost的功能.毕竟这不算是一个”轻量级” 的家伙.
但是对于上面那坨重复的东西, 我又实在是太恶心乏味了. 该我们的宏NonCopyable 出场了. 如下: ( 首先我们不使用delete 版本的NonCopyable)
// 示例: NonCopyable(Scoped_Cursor) 这样的宏必须使用放在类的private区域.#define NonCopyable(ClassName) ClassName(const ClassName &) ; \ ClassName & operator =(const ClassName &) class Scoped_Mutex{private: NonCopyable(Scoped_Mutex);}; class Scoped_Cursor{private: NonCopyable(Scoped_Cursor);};
那么这段代码写好了, 注意我们没有在NonCopyable宏定义前添加private 关键字, 所以我们要手动把NonCopyable(Scoped_Cursor) 这样的宏使用放在类的private区域. 并且要把 NonCopyable(ClassName) 处的注释写好.
以防用户不将 NonCopyable(Scoped_Cursor) 放置在private区域中.
自然, 对于用户在哪里使用NonCopyable 限制越多,说明NonCopyable越不易用. 用户或许不看注释, 根据NonCopyable的字面意思, 以为NonCopyable放置在任何域中, 都可以使NonCopyable逻辑生效.
那么好, 为了防止用户误用, 让我们在我们的NonCopyable(ClassName)宏 中添加private: 字样吧.
#define NonCopyable(ClassName) private: \ ClassName(const ClassName &) ; \ ClassName & operator =(const ClassName &)
这次可以愉快的( 肆无忌惮的 )使用我们的 NonCopyable宏了. 小试一下, 似乎乍一看, 很好很愉快. 世界很美好
class Person{public: Person(std::string name) : name_(name) { } NonCopyable(Person); std::string GetName() { return name_; }private: std::string name_;};
NonCopyable(Person) 到底放在private, 还是public区域中, 用户不用再关心了. 当然没有坑是不可能的. 请看下文 !
这时候我们在main() 函数中使用NonCopyable(Person) 后面定义的GetName(), 咦, 编译器说这是一个private 函数, 没有使用权限. 神马??? 一脸懵逼, 我明明把 GetName() 放在了public 域中的.
再回头去看看我们的NonCopyable(ClassName) 定义, 悟! 因为NonCopyable中自带了private 魔性, NonCopyable 后面的函数声明, 如果没有添加作用域关键字, 也就魔性的被连累了.
于是赶紧去NonCopyable 宏的定义处, 添加一句注释: NonCopyable 后面如果有public 函数声明, 请显示使用public: 声明! ( 这是什么鬼东西, 感觉还不如之前不自带private: 版本的NonCopyable, 于是又替换回之前的版本)
一圈下来, 因为private 的问题, 程序猿哥哥的内心是泪崩的.
4. 于是 delete 版本的 NonCopyable 横空出世. 只为我心中完美的程序猿......的程序.
#define NonCopyable(ClassName) ClassName(const ClassName &) = delete; \ ClassName & operator =(const ClassName &) = delete
这次终极版的 NonCopyable(ClassName) 定义中我们不要见鬼的private : 了, 而是使用了 = delete 声明.
因为我们之前说过 = delete 可以使用在任何作用域中 !!!
所以我们的NonCopyable(ClassName) 不再有只能在private域中使用的限制了.
终于不用再担心我的copyable鬼畜bug了.
- c++11 中函数声明 新关键字 delete的妙用之一: 搭配宏NonCopyable(ClassName) 使用
- C语言的const关键字与指针搭配使用
- C语言的const关键字与指针搭配使用
- C语言的const关键字与指针搭配使用
- C语言的const关键字与指针搭配使用
- C语言的const关键字与指针搭配使用
- c语言中assert函数的妙用
- C语言中函数的妙用
- C中函数的声明
- c语言宏的妙用--大量字符声明
- flash 中delete妙用
- VC中预处理指令与宏定义的妙用之一
- VC中预处理指令与宏定义的妙用之一
- VC中预处理指令与宏定义的妙用之一
- VC中预处理指令与宏定义的妙用之一
- C/C++中宏的妙用
- 在C编程中使用到的几个重要关键字之一extern
- 在C编程中使用到的几个重要关键字之一static
- 如何在项目中引入.h、.lib和dll、以及.cpp
- [Unity&重装系统]重装系统后Unity出现错误failed to initialize unity graphics
- 如何获取存放在Git上的项目及log日志
- TCP握手与挥手
- 第七周(2) 打卡功能
- c++11 中函数声明 新关键字 delete的妙用之一: 搭配宏NonCopyable(ClassName) 使用
- Git 忘记切换分支,误将代码提交到了别的分支!
- 流程的Python 第一章:数据模型
- linux下安装及配置jenkins
- Android Json解析中如何解析没有key的解析办法
- 二级联动实现
- Use "adb disable-verity" to disable verity.
- /Debug-iphonesimulator/✖️✖️.build/Script-817CB3AD1B3BC68D0004AFEA.sh: line 2: ./.../.framework
- mybatis学习之模糊查询用户例子