はじめに
C++で、二つのmap
やset
といった連想コンテナを一つにまとめたい場合、従来は片方のコンテナの全要素をループで取り出し、もう片方に一つずつinsert
する必要がありました。この方法では、要素のコピーや、場合によってはメモリの再確保が発生し、非効率的でした。
C++17では、この問題を解決する .merge()
というメンバ関数が導入されました。.merge()
は、コンテナの内部構造(ノード)を直接移動させるため、要素のコピーやメモリ確保を一切行わず、極めて高速にコンテナ同士を併合できます。
この記事では、.merge()
の基本的な使い方と、キーが重複した場合の挙動について解説します。
【前提】C++17とは?
C++17(シーピープラスいちなな)は、2017年に正式化されたC++言語の規格です。.merge()
はこのC++17で追加された機能のため、利用するにはC++17に対応したコンパイラ(と、その機能を有効にするための設定)が必要になります。
.merge()
を使ったサンプルコード
このコードは、std::multiset
(重複キーを許容するセット)を、std::set
(重複キーを許容しないセット)に併合する例です。
完成コード
#include <iostream>
#include <string>
#include <set> // set, multiset を使うために必要
using namespace std;
int main() {
// 併合先 (重複キーなし)
set<string> destination = {"りんご", "みかん"};
// 併合元 (重複キーあり)
multiset<string> source = {"みかん", "ぶどう", "れもん", "れもん"};
cout << "--- 併合前 ---" << endl;
cout << "destination: ";
for (const auto& item : destination) cout << item << " ";
cout << endl;
cout << "source: ";
for (const auto& item : source) cout << item << " ";
cout << endl;
// 1. source の全要素を destination に併合
destination.merge(source);
cout << "\n--- 併合後 ---" << endl;
cout << "destination: ";
for (const auto& item : destination) cout << item << " ";
cout << endl;
// 2. 併合に失敗した要素だけが source に残る
cout << "source (併合後): ";
if (source.empty()) {
cout << "空になりました。";
} else {
for (const auto& item : source) cout << item << " ";
}
cout << endl;
return 0;
}
実行結果
--- 併合前 ---
destination: りんご みかん
source: ぶどう みかん れもん れもん
--- 併合後 ---
destination: ぶどう りんご みかん れもん
source (併合後): みかん れもん
コードの解説
1. destination.merge(source);
これがコンテナを併合する核心部分です。
- 動作:
source
コンテナの各要素を一つずつ取り出し、destination
コンテナに移動させようと試みます。 - 効率性: この操作は、コンテナの内部データ(ノード)へのポインタを繋ぎ変えるだけで行われます。要素のコピーや、新たなメモリ確保・解放は一切発生しないため、非常に高速です。
- 併合元の変化: 併合に成功した要素は、
source
コンテナから削除されます。
2. キーが重複した場合の挙動
destination
(std::set
) は重複したキーを許容しません。
source
の"ぶどう"
と"れもん"
(1つ目):destination
には存在しないキーなので、併合は成功し、destination
に移動します。source
の"みかん"
と"れもん"
(2つ目):destination
には既に同じキーが存在します。そのため、これらの要素の併合は失敗し、source
コンテナにそのまま残ります。
実行結果が示すように、併合後、destination
には全てのユニークな要素が集まり、source
には destination
に既に存在していたために併合できなかった要素だけが残ります。
std::map
と std::multimap
の間でも同様に .merge()
を使用できます。
まとめ
今回は、C++17で導入された .merge()
メンバ関数を使って、map
やset
といった連想コンテナを効率的に併合する方法を解説しました。
.merge()
は、要素をコピーせず、コンテナの内部ノードを直接移動させるため非常に高速。- 併合先のコンテナが重複キーを許容しない (
set
,map
) 場合、キーが重複する要素は併合されず、元のコンテナに残り続ける。
ループを使って手動で要素を移し替えるよりも、.merge()
を使った方が、コードが簡潔になるだけでなく、パフォーマンスも大幅に向上します。