为什么将swap()实现为非抛出

时间:2017-05-18 08:08:25

标签: c++ c++03

我明白为什么有时建议为给定的类实现我们自己的swap()函数。

例如,如果我们有一个跟在 pimpl 习语之后的类,我们可能想要定义我们自己的复制构造函数,以便它执行深层复制作为参数传递的对象内容,而不是由默认复制构造函数执行的浅拷贝。这同样适用于复制赋值运算符

因为似乎std::swap()是根据(至少,当涉及到C ++ 03)而实现的复制构造函数复制赋值运算符< / i>的。执行要交换的对象的深层副本是低效的,因为只需要完成这些对象包含的指针的交换。

我的问题是为什么我们应该将swap()函数实现为 非投掷

在上面解释的情况下,我假设它只是语义:因为没有分配新的资源(即:两个现有的指针只是被交换)。抛出异常对于这种函数来说没有多大意义。

但是,在这个推理中我可能会忽略其他原因或情景。

4 个答案:

答案 0 :(得分:4)

  

我的问题是为什么我们应该将swap()函数实现为 非投掷

  1. 因为如果swap可能会抛出它是完全没用的。

    考虑:你swap两个实例,并且操作抛出。现在,他们处于什么状态?

    强有力的保证是,如果抛出异常,则没有副作用,这意味着两个原始对象都保持原始状态。

    如果我们无法满足强有力的保证,我们在很多情况下根本无法使用swap,因为没有办法从失败中有效恢复,并且没有必要在编写swap版本的时候。

  2. 因为没有理由抛出它。

    swap(现在)的简单实现使用移动赋值和构造。

    通常没有理由让一个move-constructor抛出:它没有分配任何新东西,它只是重新安置现有数据。通常没有理由进行移动分配(如上所述),并且析构函数不应该抛出 - 这些是唯一需要的操作。

答案 1 :(得分:2)

修改

我最初将问题理解为&#34;为什么要在throw函数上使用swap说明符。这个答案可能不合适,因为我没有解释为什么swap永远不会抛出。

我认为最好的答案是为什么不呢?

为什么你不指定当这个函数没有理由抛出时函数永远不会抛出?

当你没有理由抛出异常时,你应该总是将函数实现为非抛出:你为你的函数提供更强的保证。

此外,通过一些元编程,您可以利用非投掷功能。当swap / copy / move(C ++ 11)没有抛出时,一些STL类使用它来获得更快的成员函数。 (实际上,我不确定他们是否利用了在C ++ 11之前的代码中没有抛出的函数)

答案 2 :(得分:1)

对于某些类,例如

  

跟随pimpl习语的课程

我们知道swap的实现不需要抛出,因为

  

抛出异常对于这种函数没有多大意义。

如果抛出异常没有意义,那么最好不要抛出异常。

可以有其他类,例如包含没有专门交换函数的复杂成员的类,但可能会抛出复制构造函数/赋值。对于这样的类,我们无法实现从不抛出的交换。

答案 3 :(得分:1)

swap你的pImpls can't fail,在一个结构良好的程序中。 (并且在形成错误的程序中的行为无关紧要)。没有什么可以扔的