`

Item 25 不应抛出异常的swap

阅读更多

通用的swap可以在stl里找到:

有很多类使用pimpl来分离实现与接口,对它们的swap要慎重。

其实,swap只要交换二者的指针即可,不用拷贝里面的数据:

STL里的容器都是这样实现swap的。

现在假设Widget和WidgetImpl都是模板类,即:

那么,如何实现swap呢?下面这样的思路可以吗:

实际上,对模板函数的定义进行“partial specialization”在C++中是无效的。如果编译通过,说明编译器有问题。
不过,对模板类,可以进行“partial specialization”。

那么,重载swap可以解决问题吗:

但是,std这个名字空间,是不适合用上面的方法解决问题的。这属于对std空间增加了新的模板类。
而std空间的内容,只有C++委员会才有权决定。
可能上面的代码在一些编译器上可以正常运行,比如VC,但实际上属于“未定义行为”!

需要稍稍改一下:

把swap移到新的名字空间了。那么,像下面的代码:

C++将应用argument-dependent lookup (Koenig lookup)规则,进行查找,最后找到以Widget作为参数的swap函数。

从客户的角度看下面的代码:

哪一个swap会被调用到呢?有可能是std里的通用版本;有可能是std里完全特化的版本;有可能是在某个名字空间里的重载版本。
如果你想让它调用重载版本,当重载版本不存在,就调用std通用版本,那么可以像下面这样写:

C++查找swap的规则是:先在全局名字空间中找,然后在T的名字空间中找。
在std中,C++优先使用特化的版本,如果该版本存在的话。

有些程序员喜欢这样写:

std::swap(obj1, obj2);

这样就限制了swap的查找。
为了帮助这样的代码也能提高效率,你要在你的类里,定义特化的版本。

基于对“异常安全”的考虑,swap成员函数不应该抛出异常。只有这样,swap才能做到异常安全。
swap的行为基于copy ctor和拷贝赋值。这两个函数可以抛出异常。
自定义swap是为了更高的效率,应该只处理内建类型,所以不应该抛出异常。

分享到:
评论

相关推荐

    自定义泛型实现元素交换

    这个方法适用于任何实现了`IComparable<T>`接口的类型,但请注意,如果`T`不支持比较,编译器可能不会发出警告,而在运行时抛出异常。 在实际使用中,我们可以通过以下方式使用自定义的泛型列表: ```csharp ...

    Java并发编程之美_部分51

    首先,offer()方法会检查传入的元素e是否为null,如果是则抛出NullPointerException。接着,它创建一个新的Node节点,将元素e作为数据存储在Node中。然后,从当前的尾节点开始遍历,寻找插入位置。这个遍历过程由一...

    C++经典面试笔试题目

    - **noexcept**:声明函数不会抛出异常,有助于优化。 6. **C++11新特性** - **Lambda表达式**:允许在运行时定义匿名函数,简化函数对象的使用。 - **右值引用**:支持移动语义,提高资源重用效率,如`std::...

    java常见笔试题目总结

    #### 25. 如何去小数点前两位,并四舍五入? 使用`Math.round()`方法。 ```java double number = 123.456; double rounded = Math.round(number * 100.0) / 100.0; ``` #### 26. 如何取得年月日,小时分秒? 使用...

    Java 多线程与并发(15-26)-JUC集合- ConcurrentLinkedQueue详解.pdf

    - **不支持null元素**:该队列不允许存储null元素,尝试添加null元素会导致抛出`NullPointerException`。 - **高性能**:由于采用了非阻塞算法和CAS操作,相较于其他同步容器如`synchronized`或`ReentrantLock`,在...

    python入门-31-定义元组.ev4.rar

    由于元组是不可变的,尝试修改元组元素将会抛出`TypeError`。 3. **元组操作**: - **索引和切片**:可以使用索引或切片来获取元组的部分元素,如 `t[1:]` 获取从第二个元素开始的所有元素。 - **长度**:使用 `...

    C#语言教程和经典案例

    // 可能抛出异常的代码 } catch (Exception ex) { // 异常处理代码 } finally { // 无论是否发生异常都会执行的代码 } ``` - **自定义异常类**: 创建自己的异常类以提供更具体的错误信息。 - 示例: ``...

    Java concurrency集合之ConcurrentLinkedQueue_动力节点Java学院整理

    3. `add(E e)`:向队列尾部添加元素,如果队列已满,抛出异常。 4. `contains(Object o)`:检查队列是否包含指定元素。 5. `isEmpty()`:判断队列是否为空。 6. `iterator()`:获取一个迭代器,按照适当顺序遍历队列...

    C++程序设计原理与实践附录A

    // 可能抛出异常的代码 } catch (const std::exception& e) { std::cerr () ; } ``` - **throw语句**: ```cpp throw std::invalid_argument("Invalid argument"); ``` ##### 3.3 泛型编程 - **使用标准库中...

    C++ Primer中文版(第5版)李普曼 等著 pdf 1/3

    C++ Primer中文版(第5版... 18.1.1 抛出异常 684  18.1.2 捕获异常 687  18.1.3 函数try语句块与构造函数 689  18.1.4 noexcept异常说明 690  18.1.5 异常类层次 693  18.2 命名空间 695  18.2.1 命名空间定义...

    C++Primer(第5版 )中文版(美)李普曼等著.part2.rar

    C++ Primer中文版(第5版... 18.1.1 抛出异常 684  18.1.2 捕获异常 687  18.1.3 函数try语句块与构造函数 689  18.1.4 noexcept异常说明 690  18.1.5 异常类层次 693  18.2 命名空间 695  18.2.1 命名空间定义...

    Python 常用英文单词

    Python是一种广泛使用...4. `error`:在函数中抛出的异常或错误。 5. `missing`:指缺少必需的函数参数。 以上是Python编程中的一些常用英文单词及其含义,掌握这些词汇能帮助你更好地理解Python代码,提高编程效率。

    cpp_Learning:记录自己学习c++的经历

    - **throw**:抛出异常,通知上层调用者发生了错误。 7. **Visual Studio 2015开发环境**: - **IDE界面**:提供代码编辑、调试、构建等一站式服务。 - **项目与解决方案**:组织源代码,管理编译配置。 - **...

Global site tag (gtag.js) - Google Analytics