C++のstd::string::clear()はメモリの解放をしてくれない話
まあ簡単に言うと自分のC++に対する知識が浅かったって話ですが…
研究のソースでstd::string::clear()を何回か使ってメモリの解放をした「つもり」でしたが、こいつは長さを0にセットするだけでメモリ領域は食ったままらしく、結果的にメモリリーク( std::bad_alloc
)を起こして死にました。
ちなみに書いたソースはこんな感じ
class Buffer { public: Buffer(); virtual ~Buffer(); void setData(std::string data,int type); std::string getData(); int getType(); void clearData(); bool isexistData(); private: std::string data; int type; bool existData; }; Buffer::Buffer() : type(-1), existData(false) { } Buffer::~Buffer() { } void Buffer::setData(std::string data, int type) { this->data = data; this->type = type; existData = true; } std::string Buffer::getData() { return data; } int Buffer::getType() { return type; } void Buffer::clearData() { data.clear(); existData = false; } bool Buffer::isexistData() { return existData; }
こういう状況で、いくら Buffer::clearData()
を呼び出してもメモリリークを起こすので不思議だなあと思ってたら、stackoverflowにそんなことが書いてありました。
Calling std::string::clear() merely sets the size to zero. The capacity() won’t change (nor will reserve()ing less memory than currently reserved change the capacity).
stackoverflowには、解放したいんだったらBuffer::clearData()
を
void Buffer::clearData() { std::string().swap(data); existData = false; }
で行う(空文字を確保したstd::stringとのメモリ領域スワップ、スコープが終われば元々dataで確保した領域はデストラクタが呼ばれて解放される)と良いと書いてありました。
でも、この書き方だとなにやってるかわかりづらいですよね…
std::shared_ptrに変える
まあそもそもバッファなんだからshared_ptrにしろよという突っ込みが聞こえてきそうですが、その話は棚に上げて…
std::shared_ptrはじめスマートポインタは reset()
で所有権を放棄、つまるところ(shared_ptrの場合はカウンタが0であれば)明示的にメモリを開放することができます。
というわけで該当部を以下のようなコードに変更して事なきを得ましたとさ。
void Buffer::clearData() { data.reset(); existData = false; }