[[C++ Tips]] * 参照型のメンバをもつクラスのコンテナとソート [#j00f0661] ** 参照型のインスタンスをもつクラスは、通常だとvector等のコンテナに格納できない。 [#k54c94c3] // 参照型のインスタスをもつクラス struct Hoge { int& instance_; Hoge(int& i) : instance_(i) {} Hoge(const Hoge& h) : instance_(h.instance_) {} bool operator < (const Hoge& h) const { return instance_ < h.instance_; } }; std::vectorに入れてみる std::vector<Hoge> vectorhoge; int h1 = 1; vectorhoge.push_back(h); // コンパイルエラー operator =がないとvector::push_backはできない listならOK std::list<Hoge> listhoge; int h1 = 1; listhoge.push_back(h); // OK ** vectorに格納可能なリファレンスをもつクラスの定義 [#vea9f3c7] - vectorに格納(push_back, back_insert_iteratorなど)には、operator = が必要 - リファレンス型の変数は、リファレンス情報の更新はできない。代入もswapも参照先のデータにたいして行われる。 *** 禁断の技その1 [#m5f8dfc7] Hoge operator = (const Hoge& h) { memcpy(this, &h, sizeof(Hoge)); return *this; } + thisのデストラクタが呼ばれないで破棄される + オブジェクトのバイナリーコピーは非常に危険なのでダメ *** 禁断の技その2 [#f178b88a] Hoge operator = (const Hoge& h) { this->~Hoge(); new (this) Hoge(h); return *this; } + いちおう、安全。 + ハーブ・サッターさんは絶対に使うなと警告している方法 + コピーコンストラクタとデストラクタで例外を投げないことが前提。例外が発生すると破綻する。 + とりあえず、これでvectorに対する要素の追加やsortが可能になる *** コードの例 [#s7418473] #include <cstdio> #include <list> #include <vector> #include <algorithm> #include <functional> #include <iostream> // 参照を持つクラスのswap namespace { struct Hoge { int& instance_; Hoge(int& i) : instance_(i) {} Hoge(const Hoge& h) : instance_(h.instance_) {} // コピーコンストラクタとnewの第二構文を使った初期化を使って実現する。 // 例外安全ではない。コピーコンストラクタが例外を投げないことが前提 Hoge& operator = (const Hoge& h) { this->~Hoge(); // thisを破棄 new(this) Hoge(h); return *this; } // リファレンスタイプのインスタンスは通常の方法ではswapできないので、 // コピーコンストラクタとnewの第二構文を使った代入の=を使って実現する。 // 例外安全ではない。コピーコンストラクタが例外を投げないことが前提 void swap(Hoge& h) { Hoge tmp(h); // hをコピー h = *this; *this = tmp; } bool operator < (const Hoge& h) const { return instance_ < h.instance_; } }; // output用 void print(const Hoge& h) { printf("%d\n", h.instance_); } } int main(int argc, char* argv[]) { int i1 = 1; int i2 = 2; int i3 = 3; Hoge h1(i1), h2(i2), h3(i3); std::vector<Hoge> vectorhoge; vectorhoge.push_back(h3); // operator =がないとvector::push_backはでき ない vectorhoge.push_back(h2); vectorhoge.push_back(h1); std::back_inserter(vectorhoge) = h1; std::sort(vectorhoge.begin(), vectorhoge.end()); // operator =がないと vector::sortはできない std::cout << "vector sort" << std::endl; std::for_each(vectorhoge.begin(), vectorhoge.end(), print); std::list<Hoge> listhoge; listhoge.push_back(h3); listhoge.push_back(h2); listhoge.push_back(h1); std::back_inserter(listhoge) = h1; listhoge.sort(); std::cout << "list sort" << std::endl; std::for_each(listhoge.begin(), listhoge.end(), print); return 0; }