swapは心の友、C++では…

swapが心の友なのは特に C++ だ。

こんな:

ヘッダ
 1 struct myclass_impl; // opaque, implementation's detail
 2 
 3 class myclass { // final, thus we don't have virtual
 4     friend struct myclass_impl;
 5 
 6     myclass_impl* impl;
 7 public:
 8     explicit myclass();
 9     myclass(const myclass& other);
10     myclass& operator=(const myclass& rhs);
11     ~myclass();
12 
13     // ...省略...
14 };
15 // ...省略...
実装ファイル
 1 struct myclass_impl {
 2     // ...省略...
 3 };
 4 
 5 myclass::myclass()
 6     : impl(new myclass_impl())
 7 {
 8 }
 9 myclass::myclass(const myclass& other)
10     : impl(new myclass_impl(*other.impl))
11 {
12 }
13 myclass& myclass::operator=(const myclass& rhs)
14 {
15     myclass tmp(rhs); // duplicate impl from rhs to tmp
16     // take impl of tmp (originally duplicated from rhs) to this.impl
17     std::swap(this->impl, tmp.impl);
18     //tmp dtor -> delete impl originally owned by this.
19     return *this;
20 }
21 myclass::~myclass()
22 {
23     delete impl;
24 }
25 // ...省略...

この swap の活用方法がどんな理由で「優れている」のかについては、とにかく以下で「楽しく」読める:

Exceptional C ―47のクイズ形式によるプログラム問題と解法 (C in‐Depth Series)

More Exceptional C さらに40のクイズ形式によるプログラム問題と解法 (C In‐Depth Series)


既にかなり古い本になってしまっているため、C++11 しか知らないような人はちょっと注意はした方が良いけれど、ただ、これはもはや「古典」とも言うべき名著。是非手にとってみて欲しい。

読んでる暇がない、という人のためにはポイントだけ。一に、「例外安全」。二に、「効率」。「ポインタを交換する」ことは、限りなくゼロオーバヘッドで、かつ、例外を起こさない「アトミックな」操作であるという点がポイント。であるから、STL の全てのコンテナに swap が提供されている。


で、まぁ「ポインタの swap」でなくても swap なんかは多用はするわけなんだけれども、ただ、それを理由に「心の友よ」とまでは言えんでしょう。なくても「面倒」なだけだから致命傷ではないし、ないなら書けばいいだけ、程度の話。生の C しかなかった頃は標準の swap なんかなかったので、皆自分でマクロを書いてたわけで。

さて。これ書いたときにふと、「はて、python で swap ってどう書くんだっけな?」が頭をよぎった、と書いた。これ、一般解は実に簡単なことであったわ:

1 a = 1
2 b = 2
3 
4 a, b = b, a

基本 Python 脳には慣れてるつもりではあるんだけれど、C++ 脳も抜けないもんで、こういう FAQ 的なことも割とよく忘れるの…。あ、FAQ もたまに読んだ方がいーよ、アタシのようにバカにならないように。