考虑实现一个不抛异常的swap
Effective C++:参考自harttle land
类的swap实现与STL容器是一致的:提供swap
成员函数, 并特化std::swap
来调用那个成员函数。
class Widget {
public:
void swap(Widget& other){
using std::swap; // 使得`std::swap`在该作用域内可见
swap(pImpl, other.pImpl);
}
}; namespace std {
template<>
void swap<Widget>(Widget& a, Widget& b){
a.swap(b); // 调用成员函数
}
}
类模板的Swap
1.下面代码不能通过编译。C++允许偏特化类模板,却不允许偏特化函数模板
template<typename T>
class WidgetImpl { ... }; template<typename T>
class Widget { ... }; namespace std {
template<typename T>
// swap后的尖括号表示这是一个特化,而非重载。
// swap<>中的类型列表为template<>中的类型列表的一个特例。
void swap<Widget<T> >(Widget<T>& a, Widget<T>& b){
a.swap(b);
}
}
2. 不能向STL里面添加新的东西,重载版本。C++标准中,客户只能特化std
中的模板,但不允许在std
命名空间中添加任何新的模板,会引发未定义
namespace std {
template<typename T>
// 注意swap后面没有尖括号,这是一个新的模板函数。
// 由于当前命名空间已经有同名函数了,所以算函数重载。
void swap(Widget<T>& a, Widget<T>& b){
a.swap(b);
}
}
正确做法是不在std
下添加swap
函数了,把swap
定义在Widget
所在的命名空间中,或直接在global命名空间:
namespace WidgetStuff {
template<typename T>
class Widget {
public:
void swap(Widget& other){
using std::swap;
swap(pImpl, other.pImpl);
}
}; template<typename T>
void swap(Widget<T>& a, Widget<T>& b){
a.swap(b);
}
}
似乎类的Swap也只需要在同一命名空间下定义swap
函数,而不必特化std::swap
。 但是!有人喜欢直接写std::swap(w1, w2)
,调用std::swap,
特化WidgetStuff::swap
不会得到调用。std::swap
可以让你的类更加健壮。此时,C++编译器会优先调用指定了T的std::swap特化版
,其次是T
所在命名空间下的对应swap
函数, 最后才会匹配std::swap
的默认实现。
应用:
赋值构造函数的swap写法:解决自己赋值自己的问题
class Widget
{
public:
Widget():id(), size(), data(NULL){}
Widget(int val)
{
id = val;
size = id+;
data = new int [size];
}
Widget(const Widget &rhs) //deep copy
{
id = rhs.id;
size = rhs.size;
data = new int[size];
memcpy(data, rhs.data, sizeof(int)*size);
}
friend void swap(Widget & lhs, Widget &rhs)
{
using std::swap;
swap(lhs.id, rhs.id);
swap(lhs.size, rhs.size);
swap(lhs.data, rhs.data);
}
/*
Widget & operator = (Widget rhs) //pass by value, copy构造后swap
{
swap(*this, rhs);
return *this;
}
*/
Widget& operator= (const Widget &rhs) //pass by 引用
{
Widget tmp(rhs);
swap(*this, tmp);
return *this;
}
~Widget()
{
std::cout<<"id:"<< id << " destructor called..." << std::endl;
if(data != NULL)
{
delete [] data;
data = NULL;
}
}
int getId() const
{
return id;
}
int getSize() const
{
return size;
} private:
int *data;
int id;
int size;
};
如何实现Swap呢?总结一下:
- 提供一个更加高效的,不抛异常的共有成员函数(比如
Widget::swap
)。 - 在你类(或类模板)的同一命名空间下提供非成员函数
swap
,调用你的成员函数。 - 如果你写的是类而不是类模板,请偏特化
std::swap
,同样应当调用你的成员函数。 - 调用时,请首先用
using
使std::swap
可见,然后直接调用swap
。
考虑实现一个不抛异常的swap的更多相关文章
- EC读书笔记系列之13:条款25 考虑写出一个不抛异常的swap函数
记住: ★当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定其不抛出异常 ★若你提供一个member swap,也该提供一个non-member swap来调用前者.对于cla ...
- Effective C++:条款25:考虑写出一个不抛异常的swap函数
(一) 缺省情况下swap动作可由标准程序库提供的swap算法完毕: namespace std { template<typename T> void swap(T& a, T& ...
- 【25】考虑写出一个不抛异常的swap函数
1.swap交换对象值,std提供了实现方法模版的实现,它的实现是交换对象值. namespace std { template<typename T> void swap(T& ...
- [Effective C++ --025]考虑写出一个不抛异常的swap函数
引言 在我的上一篇博客中,讲述了swap函数. 原本swap只是STL的一部分,而后成为异常安全性编程的脊柱,以及用来处理自我赋值可能性. 一.swap函数 标准库的swap函数如下: namespa ...
- Effective C++ -----条款25:考虑写出一个不抛异常的swap函数
当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常. 如果你提供一个member swap,也该提供一个non-member swap用来调用前者.对于cla ...
- 《Effective C++》item25:考虑写出一个不抛异常的swap函数
std::swap()是个很有用的函数,它可以用来交换两个变量的值,包括用户自定义的类型,只要类型支持copying操作,尤其是在STL中使用的很多,例如: int main(int argc, _T ...
- Effective C++ Item 25 考虑写出一个不抛异常的swap函数
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛 ...
- 【JAVA】学习路径64-补充-编写一个会抛异常的方法
有一些方法,在调用的时候有可能会出错,所以我们使用这些方法的时候会使用try catch. 比如InputStream里面的read()方法等等,那么这些方法是怎么实现抛异常的效果的呢? 能抛异常的方 ...
- 不抛异常的swap函数
namespace AStuff{ template<typename T> class A { public: void swap(A *other) { using std::swap ...
随机推荐
- cu命令
选项: -b:仅显示行中指定直接范围的内容: -c:仅显示行中指定范围的字符: -d:指定字段的分隔符,默认的字段分隔符为“TAB”: -f:显示指定字段的内容: -n:与“-b”选项连用,不分割多字 ...
- web页面加载、解析、渲染过程
仅做学习参考,侵权删 原文链接:风吹De麦浪 https://www.cnblogs.com/CandyManPing/p/6635008.html 一.浏览器 浏览器的主要功能是将用户选择的we ...
- bootstrap简单使用布局、栅格系统、modal标签页等常用组件入门
<!DOCTYPE html> <html> <head> <title>bootstrap</title> <!-- 引入boots ...
- LabVIEW版本控制(转)
原文转自https://www.cnblogs.com/EltonLiang/p/7105034.html 在我们工作中,必然会遇到代码的多个版本问题,也必然会遇到版本控制问题.如果所在的公司具有良好 ...
- LabVIEW---vi图标和符号的制作
前言: 使用图形化设计语言进行开发时候,为VI添加说明的一个重要的方法是为其建立一个形象的图标,每个VI都在前面板后程序框图的右上角有一个图标,它是VI的图形化表示.如果VI当作子VI调用,该图标就会 ...
- poj1562 Oil Deposits 深搜模板题
题目描述: Description The GeoSurvComp geologic survey company is responsible for detecting underground o ...
- kindeditor用法简单介绍(转)
1,首先去官网下载http://www.kindsoft.net/ 2,解压之后如图所示: 由于本人做的是用的是JSP,所以ASP,PHP什么的就用不上了,直接把那些去掉然后将整个文件夹扔进Myecl ...
- linux 源码安装PHP
解压: 解压完: configure: configure成功: make: make完成: 安装完成!!! 测试: 需要./bin/php来运行php 想要任何目录输入PHP就能使用php 方法一: ...
- Software tips
1.Microsoft office professional plus 2013秘钥 PD3W7-NVGG7-YKGQX-7CRDG-J2MG7(test success)MTGRC-8BM6H-W ...
- Brup Suite 渗透测试笔记(六)
接上次笔记这章记payload的类型分类做一说明: 1.simplelist是一个简单的payload类型,通过配置一个字符串作为payload,也可以手动添加字符串列表. 2.运行文件 Runtim ...