質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

26217閲覧

std::listにおけるイテレータの指定の仕方

RyuSA

総合スコア131

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/05/22 04:46

###前提
std::listにおいて、指定したindexに要素にアクセスする際に適切な記述の仕方がわかりません。

cpp

1std::list lst{1,2,3,4,5,6,7,8,9}; 2// 1と表示される 3std::cout << *(lst.begin()) << std::endl; 4// でも、次のはエラー 5std::cout << *(lst.begin()2) << std::endl;

どのように記述すればよいのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

std::listコンテナはstd::vectorや配列と違って、ランダムアクセスができません。そのため、N回だけイテレータを進めて要素を参照する必要があります。
そのような用途には、std::next()関数を使用できます。

cpp

1#include <iostream> 2#include <list> 3#include <iterator> // std::next()関数が所属するヘッダ 4 5int main() 6{ 7 std::list<int> lst{1,2,3,4,5,6,7,8,9}; 8 9 // 1と表示される 10 std::cout << *(lst.begin()) << std::endl; 11 12 // 3と表示される 13 std::cout << *std::next(lst.begin(), 2) << std::endl; 14}

この関数は、指定されたイテレータをN回進めたイテレータを返します。(指定したイテレータ自体は書き換えない)

std::next()をサポートしていない古いコンパイラの場合は、std::advance()関数を使用します。こちらは指定したイテレータ自体をN回進めます。

cpp

1#include <iostream> 2#include <list> 3#include <iterator> // std::advance()関数が所属するヘッダ 4 5int main() 6{ 7 std::list<int> lst{1,2,3,4,5,6,7,8,9}; 8 9 // 1と表示される 10 std::cout << *(lst.begin()) << std::endl; 11 12 // 3と表示される 13 std::list<int>::iterator it = lst.begin(); 14 std::advance(it, 2); // itを2回進める 15 std::cout << *it << std::endl; 16}

投稿2017/05/22 08:14

編集2017/05/22 15:40
faithandbrave

総合スコア132

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

haru666

2017/05/22 08:17

おお…nextあったんですね。なんでないんだろうと思ってたんですが、C++11から増えてたんですね。 いいですね!
guest

0

ベストアンサー

iteratorを使って回数分移動するしかありません。
これを変わりにしてくれるものにstd::advanceがあります。

C++

1UINT index; 2auto it = lst.begin(); 3 4// このようにする 5for (int i=0; i < index; ++i) 6{ 7 it++; 8} 9 10// 代わりに以下のようにかけます。 11std::advance(it, index);

forループにせよadvanceにせよ単純にiteratorをインクリメントするだけなので
インデックスアクセスで範囲外を参照しないようにsizeと事前に比較しておいてください。

if (lst.size() <= index) return;

見ての通りlistにおける要素の取得は高コストです。
ランダムアクセスを主目的とする場合はvector等別のコンテナを使った方がいいでしょう。
基本的には編集可能なqueueと思って使用するのがベターです。

投稿2017/05/22 05:34

haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2017/05/22 06:36

ご指摘の通り、listにおける要素の取得は高コストです。 が、イテレータをn個進めるのは「次の要素に移動する」すなわちp = p->next をn回繰り返すだけで、 やってらんないほど遅いわけではありません。あくまでRandomAccessIteratorと比べれば高コストってことで。 listのコストはむしろ「ひとつの要素ごとにポインタふたつ余計に必要」っていうメモリ効率の方が問題大きいかもです。
haru666

2017/05/22 08:15 編集

深く考えないなら大体vectorの方が問題が少ない、と思っているから上記のように書きました。 無作法な反論をお許し下さい。 値の保持の仕方こそこの両コンテナの重要な違いであって、メモリコストは私はあまり問題視していません。 vectorは値の挿入によってオブジェクトの配置が換わる可能性があります。 listなら変わりません。これはあまり話題にされない気がしますが、最も重要な違いです。 コスト面で言えば、値の挿入時、vectorはcapacityの拡張で内部配列の移動によるコピーコストが発生する可能性があります。 また、オブジェクトのメモリ上の配置が換わってしまう可能性があります。 listを使えばこのコストは発生しません。 ランダムアクセスを元にした二分木のようなアルゴリズムがあります。 ランダムアクセスをベースとした仕組みは直観的で作りやすいため、度々使われます。 一方、listを使う場合には直接要素のポインタ/イテレータを保持するのが再アクセス手段のベストプラクティスです。 そういった操作に慣れてない多くの人はランダムアクセスによってコンテナ内の要素に再アクセスしようとします。 listで可能なイテレータの保存という行為はvectorではできません。 先に述べたように、vectorでは値の挿入時、イテレータがズレてしまう可能性があるからです。 これを嫌ってunique_ptrを使ってオブジェクトをヒープ内にラップし、vector配列にしてしまうこともあります。 listではそもそもそんな配慮が不要です。 シーケンシャルアクセスするだけならどちらでもよいのです。 しかし…listは使いづらいし、正しくパフォーマンスを出すのが難しい。 特に、リファレンスを読まない作業者がチーム内にいると混乱の元かな、と。 このため、基本的にランダムアクセスを理由にvectorをオススメしている次第です。
episteme

2017/05/22 08:20

ぃぇぃぇ、無作法な反論だなんてとんでもない。 スピードとメモリ効率なら各要素を連続に配置するvectorが一番で、そのかわりイテレータがしょっちゅう無効になる。これの対極(?)にあるのがlistってことで、全面的に同意します。 「コンテナにどれ使うか迷ったらひとまずvector使っとけ」は大抵の場合正解ですし。
guest

0

こんには。

std::list lst{1,2,3,4,5,6,7,8,9};

は下記の間違いですね?

std::list<int> lst{1,2,3,4,5,6,7,8,9};

std::listのbegin()はイテレータを返却しますが、それはbidirectional_iteratorですので、+整数演算をサポートしていません。一旦変数へ獲得し、2回++しましょう。

C++

1auto itr = lst.begin(); 2++itr; 3++itr; 4std::cout << *itr << std::endl;

全てのコンテナが同じ機能をサポートすれば良いのにとも思いますが、STLは性能が出ない機能はサポートしない方針のようです。性能がでなくても問題ないのであればコンテナを派生して、必要な機能を追加するのが良いと思います。

もしくは、random_access_iteratorをサポートしているstd::vector<>std::deque<>に代えることも考えられます。

アプリケーションの要求に応じてどの性能を最大化するのかにより適切なコンテナを選択するのがSTLの思想と思います。

投稿2017/05/22 05:32

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

faithandbrave

2017/05/22 08:23

C++17では std::list lst{1,2,3,4,5,6,7,8,9}; は妥当なコードになりますので、使用しているコンパイラのバージョンによっては通りますね。クラステンプレートの型推論機能によるものです。
Chironian

2017/05/22 09:47

faithandbraveさん、コメントありがとうございます。 なるほど、そう言えばコンストラクタで暗黙の実体化ができるようになる話を聞いた記憶が有ります。既に使えるようになっていたのですね。時の流れは速い。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問