为什么将 swap() 实现为非抛出
Why implementing swap() as non-throwing
我理解为什么有时建议为给定的 class 实现我们自己的 swap()
函数。
例如,如果我们在 pimpl 习语之后有一个 class,我们可能想要定义我们自己的 复制构造函数,以便它对作为参数传递的对象的内容执行深度复制,而不是执行 浅复制 默认复制构造函数。这同样适用于 复制赋值运算符 .
因为 std::swap()
似乎是根据(至少,当涉及到 C++03 时) 复制构造函数 和 复制赋值运算符。执行要交换的对象的深拷贝是低效的,因为只需要交换这些对象包含的指针。
我的问题是为什么我们应该将swap()
函数实现为非抛出一个.
在上面解释的情况下,我认为这只是语义问题:因为没有分配新资源(即:两个现有指针只是被交换)。这样的函数抛出异常意义不大。
但是,我在这个推理中可能忽略了其他原因或场景。
编辑
我最初将这个问题理解为“为什么要在 swap
函数上使用 throw
说明符。这个答案可能与主题无关,因为我没有解释为什么 swap
从不抛出。
我认为最好的答案是为什么不呢?。
当这个函数没有理由抛出时,为什么不指定该函数永远不会抛出?
当函数没有理由抛出异常时,你应该始终将函数实现为非抛出:你为你的函数提供了更强的保证。
此外,通过一些元编程,您可以利用函数的非抛出特性。当 swap/copy/move(C++11) 不抛出时,一些 STL 类 使用它来获得更快的成员函数。 (实际上我不确定他们是否利用了在 C++11 之前的代码中不会抛出的函数)
对于一些类例如
a class following the pimpl idiom
我们知道swap
的执行不需要抛出因为
It wouldn't make much sense for such a kind of function to throw an exception.
当抛出异常没有意义的时候,那么最好不要抛出异常。
可能还有其他 类,例如那些包含没有专门交换函数的复杂成员,但可能会抛出复制构造函数/赋值。对于这样的 类 我们无法实现永不抛出的交换。
swap
在你的 pImples can't fail 中,在一个格式良好的程序中。 (并且格式错误的程序中的行为无关紧要)。没什么可扔的
My question is why we should implement our swap()
function as a non-throwing one
因为swap
万一抛出就完全没用了
考虑:您 swap
两个实例,操作抛出。现在,他们处于什么状态?
强有力的保证是在抛出异常时没有副作用,这意味着两个原始对象都保留在其原始状态。
如果我们不能满足强保证,在很多情况下我们根本无法使用swap
,因为没有办法从失败中有效地恢复,并且根本没有必要编写 swap
的那个版本。
因为没有理由抛出。
swap
(现在)的简单实现使用移动赋值和构造。
移动构造函数通常没有理由抛出:它不分配任何新内容,它只是重新安置现有数据。移动赋值通常没有理由抛出(如上所述),并且析构函数永远不应该抛出 - 这些是唯一需要的操作。
我理解为什么有时建议为给定的 class 实现我们自己的 swap()
函数。
例如,如果我们在 pimpl 习语之后有一个 class,我们可能想要定义我们自己的 复制构造函数,以便它对作为参数传递的对象的内容执行深度复制,而不是执行 浅复制 默认复制构造函数。这同样适用于 复制赋值运算符 .
因为 std::swap()
似乎是根据(至少,当涉及到 C++03 时) 复制构造函数 和 复制赋值运算符。执行要交换的对象的深拷贝是低效的,因为只需要交换这些对象包含的指针。
我的问题是为什么我们应该将swap()
函数实现为非抛出一个.
在上面解释的情况下,我认为这只是语义问题:因为没有分配新资源(即:两个现有指针只是被交换)。这样的函数抛出异常意义不大。
但是,我在这个推理中可能忽略了其他原因或场景。
编辑
我最初将这个问题理解为“为什么要在 swap
函数上使用 throw
说明符。这个答案可能与主题无关,因为我没有解释为什么 swap
从不抛出。
我认为最好的答案是为什么不呢?。
当这个函数没有理由抛出时,为什么不指定该函数永远不会抛出?
当函数没有理由抛出异常时,你应该始终将函数实现为非抛出:你为你的函数提供了更强的保证。
此外,通过一些元编程,您可以利用函数的非抛出特性。当 swap/copy/move(C++11) 不抛出时,一些 STL 类 使用它来获得更快的成员函数。 (实际上我不确定他们是否利用了在 C++11 之前的代码中不会抛出的函数)
对于一些类例如
a class following the pimpl idiom
我们知道swap
的执行不需要抛出因为
It wouldn't make much sense for such a kind of function to throw an exception.
当抛出异常没有意义的时候,那么最好不要抛出异常。
可能还有其他 类,例如那些包含没有专门交换函数的复杂成员,但可能会抛出复制构造函数/赋值。对于这样的 类 我们无法实现永不抛出的交换。
swap
在你的 pImples can't fail 中,在一个格式良好的程序中。 (并且格式错误的程序中的行为无关紧要)。没什么可扔的
My question is why we should implement our
swap()
function as a non-throwing one
因为
swap
万一抛出就完全没用了考虑:您
swap
两个实例,操作抛出。现在,他们处于什么状态?强有力的保证是在抛出异常时没有副作用,这意味着两个原始对象都保留在其原始状态。
如果我们不能满足强保证,在很多情况下我们根本无法使用
swap
,因为没有办法从失败中有效地恢复,并且根本没有必要编写swap
的那个版本。因为没有理由抛出。
swap
(现在)的简单实现使用移动赋值和构造。移动构造函数通常没有理由抛出:它不分配任何新内容,它只是重新安置现有数据。移动赋值通常没有理由抛出(如上所述),并且析构函数永远不应该抛出 - 这些是唯一需要的操作。