スポンサーリンク

| キーワード:,

std::removeの挙動

俺がstd::removeを理解できないのはどう考えても仕様が悪い。

というわけで、std::removeの挙動の再確認。

std::removeは、第一引数から第二引数までのコンテナ内の、第三引数で指定された値を削除する(嘘)、STLの関数だ。

 

今回使うのは以下。removeのためにalgorithm。iteratorはstd::beginを気分で使う。

#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>

 

 

 

まず配列を用意して初期化する。

std::vector<int> vec = { 1, 2, 3, 2 , 4, 2 , 5 };

for (auto i = std::begin(vec); i != std::end(vec); i++){
	std::cout << *i << std::endl;
}

結果は、

1
2
3
2
4
2
5

 

 

 

 次に、この配列の値2に対してstd::removeをかける

auto end = std::remove(std::begin(vec), std::end(vec), 2);

for (auto i = std::begin(vec); i != std::end(vec); i++){
	std::cout << *i << std::endl;
}

 結果は、

1
3
4
5
4
2
5

 

 

 

さあ、もう訳がわからない。消えたはずの2は残っていてその割に個数は減っていてその上位置まで変わっていて、さらにいじったつもりのない4と5が増えている。

 

 

Erase-Removeエディオムというのがあり、eraseと併用すれば消える。

vec.erase(
	std::remove(
		std::begin(vec),
		std::end(vec),
		2
	),
	std::end(vec)
);

for (auto i = std::begin(vec); i != std::end(vec); i++){
	std::cout << *i << std::endl;
}

 

 

 

これはつまりこういうことだ。

 

std::removeは、指定した削除対象の値以外のものを配列の左側に再配置する。

そして戻り値として、必要なデータが入っている領域の次の値へのイテレータを返す。

std::removeが行うのはコンテナの中の値の書き換えだけなので、高速だが、そのままではいわば「破棄推奨領域」が生じてしまう

(※) end2 = std::remove(begin,end,value);というようにして、以後の処理を begin~end2の範囲に対して行うようにすれば、消えたものとして処理できる。

この破棄推奨領域を削除する行為は、確保されているメモリ領域の変更なのでstd::eraseを用いる必要がある。

removeerase

 

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: