■
boost::checked_delete(r) の存在する理由について説明した。じゃあ、現実的にそれが必要とされるのはどんな場面なのか。
Pimpl イディオム(google:Pimpl idiom)というものがある。インクルード地獄から脱出するためのこのイディオムの、もっとも単純な例を示す。この単純な例は、どのように改善できるだろうか。
まずはヘッダファイル、
#ifndef A_HEADER
#define A_HEADERclass A {
class Impl;
Impl* impl_;public:
A();
~A();void act();
};#endif
次にソースファイル、
#include <iostream>
#include "A.hpp"class A::Impl {
// member variables and methods...
public:
Impl()
// initialize member variables...
{
std::cout << "A::Impl::(constructor)" << std::endl;
}~Impl() {
std::cout << "A::Impl::(destructor)" << std::endl;
}void act() {
// do something...
}
};A::A()
: impl_(new Impl()) {}A::~A() {
delete impl_;
}void
A::act() {
impl_->act();
}
このイディオムでは、class A の実装は、internal class A::Impl のなかに隠蔽されている。これによって、private なメンバ変数や関数の追加に際して、ヘッダファイルを変更する必要がなくなる。
さて、賢明な俺たちは、delete impl_; なんてわざわざ書かなければならないのは間尺に合わないと考えるだろう。もし書き忘れたらメモリが解放されない。メモリなんか腐るほどあるから気にしなくたっていいけど(ブルジョア!)、やっぱりなんだか気持ち悪い。よし、std::auto_ptr を使うことにしよう。
#ifndef A_HEADER
#define A_HEADER#include <memory>
class A {
class Impl;
std::auto_ptrimpl_; public:
A();
~A();void act();
};#endif
そして、デストラクタの実装は、
A::~A() {
// noop
}
からっぽだ。ってことは、面倒だから、このデストラクタは省略しちまおう。しかし、ここに罠がある。しーぷるぷるがぷるぷるしてるのは、まさにこのような罠をその理由としているのだ。