C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

STLイテレータ間の減算

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■89983 / inTopicNo.1)  STLイテレータ間の減算
  
□投稿者/ ひくいち (1回)-(2019/01/28(Mon) 14:16:17)

分類:[C/C++] 

2019/01/28(Mon) 14:17:28 編集(投稿者)
2019/01/28(Mon) 14:17:23 編集(投稿者)

STL標準講座という書籍内に

vector<char> v, v2(100);
vector<char>::iterator p;

//vに適当な文字を詰める処理

p = remove_copy(v.begin(), v.end(), v2.begin(), ' ');
for(size_t i=0; i<p-v2.begin(); i++) cout << v2[i];//' 'を除いた文字列の表示

というコードが掲載されているのですが、
i < p-v2.begin()の部分で
イテレータ間の減算結果を数値型と比較する意味が分かりません。
1. p-v2.begin()の型は何になりますでしょうか?
2. 数値型と比較する理由を知りたいです。
3. こういった場合型を確認する方法をご教示いただけますでしょうか。

以上、宜しくお願い致します。


引用返信 編集キー/
■89985 / inTopicNo.2)  Re[1]: STLイテレータ間の減算
□投稿者/ 774RR (664回)-(2019/01/28(Mon) 15:26:27)
あんまりいいサンプルじゃないな・・・オイラならそのコードをサンプルとして提示しない。
とりあえず質問に答えるなら

普通の配列ならわかる? &a[10] - &a[0] の差は 10 (ptrdiff_t 型) に納得できるのなら
提示コードの p は &v2[最後の有効要素の次] つまり p-v2.begin() は有効要素数
(この減算が許されるのは vector だからで、一般的なイテレータではダメ。 std::distance を使うべし)
for (i=0; i<要素数; ++i) { ... } というのは C で配列を扱うときの常套手段。

https://cpprefjp.github.io/reference/iterator/distance.html

1. iterator_traits<T>::difference_type 型。この場合は単に ptrdiff_t 型。まあ普通に int 型だ。
2. 有効要素数までループしたいから
3. #include <typeinfo> したうえで typeid().name() するとよい
std::cout << typeid(p-v2.begin()).name() << std::endl;
gcc なら i と表示されるだろう。 Visual C++ なら int と表示されるだろう。

C++03 向けサンプルとしてオイラが提示するなら
std::copy(v2.begin(), std::remove_copy(v.begin(), v.end(), v2.begin(), ' '),
std::ostream_iterator<char>(std::cout)));
かな・・・既に copy + ostream_iterator イディオムを知ってる人向けになっちゃうか。

引用返信 編集キー/
■90014 / inTopicNo.3)  Re[2]: STLイテレータ間の減算
□投稿者/ ひくいち (2回)-(2019/01/30(Wed) 17:24:29)
No89985 (774RR さん) に返信

ご回答ありがとうございます。
prtdiff_t型を知りませんでした。コードの意図が理解できました。
サンプルありがとうございます。こちらの方がシンプルに書けわかりやすいです。
解決済み
引用返信 編集キー/
■90024 / inTopicNo.4)  Re[3]: STLイテレータ間の減算
□投稿者/ 774RR (665回)-(2019/01/31(Thu) 11:04:44)
わかってると思うけど、ポインタの引き算(イテレータの引き算)結果は「要素数」っす。
型が char でも int でも double でも、自作クラスでも、要素数であってバイト数じゃない。
4つ戻るような場合に -4 を保持できる必要があるので ptrdiff_t は符号付き。

閑話休題・以下駄文

こう書いたほうがわかりやすいし実用的なのだろうけど

std::vector<char> v2; // 初期要素数0
std::remove_copy(v.begin(), v.end(), std::back_inserter(v2), ' '); // 自動拡張
std::copy(v2.begin(), v2.end(), std::ostream_iterator<char>(std::cout));
std::cout << std::endl;

驚いたことに gcc-4 では remove_copy + back_inserter が通らないっす。
(ネット接続禁止の実験PCに入っている古い cygwin でエラーとなった)
今の cygwin64 な gcc-7.4.0 ではおっけー。この本の書かれた当時はダメだったのかも。

今っつか C++11 や C++14 が使える開発現場では STL のその辺の機能を使う機会は激減してる。
範囲 for とかラムダ式が正式に導入されたあとはそっち使ったほうが圧倒的に楽。
(組み込み系だと故意に古い開発環境を維持していたりするが PC レベルなら更新すべき)
現代 C++ の学習に使う参考書としてはやはり古さを感じるっすね。
もっと新しい本(なり web 記事なり)を探したほうが良い。

for (const auto& c : v2) std::cout << c; // のほうが絶対わかりやすくてタイプ量も少

解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ