1. 導入
C++でプログラミングをしていると、2つのコンテナ(std::vectorやstd::mapなど)の中身を入れ替えたいという場面によく遭遇します。単純に代入演算子(=)を使ってしまうと、すべての要素がコピーされるため、要素数が多いほど処理時間がかかり、メモリ消費も増大します。
今回紹介する「swap()」メソッドは、コンテナの中身を実質的に「ポインタの付け替え」で行うため、要素数に関わらず O(1) の定数時間で完了します。パフォーマンスを意識するC++エンジニアにとって、必須のテクニックです。
2. 基礎知識
C++の標準ライブラリ(STL)のコンテナは、内部的に動的なメモリ確保を行っています。例えば std::vector の場合、データ本体はヒープ領域に確保されており、コンテナオブジェクト自体はその場所を示すポインタやサイズ情報を持っています。
swap() を呼び出すと、これらの「管理情報」を入れ替えるだけで済みます。データ本体のコピーが発生しないため、どれほど巨大なデータであっても一瞬で入れ替えが完了します。
3. 実装/解決策
使い方は非常にシンプルです。対象のコンテナに対して .swap() メソッドを呼び出すだけです。また、std::swap(a, b) という汎用的な関数も用意されており、どちらを使っても結果は同じです。ただし、特定のコンテナ専用の .swap() メソッドの方が、読みやすさや意図の明確化の面で好まれることが多いです。
4. サンプルプログラム
以下のコードは、std::vectorの中身を入れ替える例です。コピーが発生していないことを確認してみてください。
include <iostream>
include <vector>
include <algorithm>
int main() {
// 巨大なデータを持つベクターを2つ用意
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = {10, 20, 30, 40, 50};
// v1とv2の中身を入れ替える
// この操作はコピーではなく内部ポインタの交換のみなので高速
v1.swap(v2);
// 結果の出力
std::cout << "v1の中身: ";
for (int x : v1) std::cout << x << " "; // 10 20 30 40 50 と表示される
std::cout << "\n";
std::cout << "v2の中身: ";
for (int x : v2) std::cout << x << " "; // 1 2 3 と表示される
std::cout << "\n";
return 0;
}
5. 応用・注意点
swap() を使う際に注意すべき点は、「参照やイテレータの無効化」です。入れ替えを行った後、以前のコンテナを指していたイテレータやポインタ、参照は、入れ替え後のコンテナの要素を指すようになります。これを意図せずに行うと、バグの原因になります。
また、C++11以降は「ムーブセマンティクス」が導入されたため、std::move を使った代入も一般的ですが、コンテナの入れ替えにおいては依然として swap() が最も直感的で意図が明確です。コードレビューで「コピーが発生していないか?」と指摘された際は、この swap() の活用をぜひ検討してみてください。

コメント