我明白为什么有时建议为给定的类实现我们自己的swap()
函数。
例如,如果我们有一个跟在 pimpl 习语之后的类,我们可能想要定义我们自己的复制构造函数,以便它执行深层复制作为参数传递的对象内容,而不是由默认复制构造函数执行的浅拷贝。这同样适用于复制赋值运算符。
因为似乎std::swap()
是根据(至少,当涉及到C ++ 03)而实现的复制构造函数和复制赋值运算符< / i>的。执行要交换的对象的深层副本是低效的,因为只需要完成这些对象包含的指针的交换。
我的问题是为什么我们应该将swap()
函数实现为 非投掷 。
在上面解释的情况下,我假设它只是语义:因为没有分配新的资源(即:两个现有的指针只是被交换)。抛出异常对于这种函数来说没有多大意义。
但是,在这个推理中我可能会忽略其他原因或情景。
答案 0 :(得分:4)
我的问题是为什么我们应该将
swap()
函数实现为 非投掷
因为如果swap
可能会抛出它是完全没用的。
考虑:你swap
两个实例,并且操作抛出。现在,他们处于什么状态?
强有力的保证是,如果抛出异常,则没有副作用,这意味着两个原始对象都保持原始状态。
如果我们无法满足强有力的保证,我们在很多情况下根本无法使用swap
,因为没有办法从失败中有效恢复,并且没有必要在编写swap
版本的时候。
因为没有理由抛出它。
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,在一个结构良好的程序中。 (并且在形成错误的程序中的行为无关紧要)。没有什么可以扔的