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

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

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

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

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

Q&A

解決済

3回答

458閲覧

c++ : std::stack のデータの保持の仕方がわからない。

yoshiki_iwasa

総合スコア23

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

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

0グッド

0クリップ

投稿2020/11/07 04:32

c++ の stack を自分で実装しようとして挙動を調べています。その過程で生まれた疑問です。

Q:stack は 値を保持する配列はどうやって宣言しているのでしょうか? あわせて、push()の挙動はどうなるのでしょうか?

ソースコードを追ったのですが、わかりませんでした。

自分が、思うに、選択肢は2つだと思います

値を保持する配列の大きさを静的に設定-> push するたび、配列のお尻に一個追加。
(例えばこのサイト: https://www.cprogramming.com/tutorial/computersciencetheory/stackcode.html)

配列を動的に確保-> push するたび、大きさを一つ増やした配列を作り直して、値をコピー

実際のところはどうなのでしょうか?

 の場合、stack インスタンスを宣言するたびに常に大きなメモリを確保しないといけないのでメモリがもったいないですよね。

でも

 の場合は、値をコピーするたびに、配列の大きさ回コピーの処理をしないといけないので、以下のような処理がタイムアウトすると思いました。(実際はタイムアウトしません....)

C++

1#include <iostream> 2#include <stack> 3 4int main() 5{ 6 std::stack<char> n; 7 8 for (size_t i = 0; i < 10000000; i++) 9 { 10 n.push('a'); 11 } 12 13 14}

どなたかお力を貸してくださいm(__)m

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

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

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

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

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

guest

回答3

0

std::stack はデフォルトでは std::deque をベースにすることになっています。 一般的には std::deque はリングバッファを使いつつ、足りなくなれば伸ばすという戦略を取ることになるでしょう。 実体としては std::vector に近いはずです。

スタックのメモリ管理の戦略を考えるとすると、以下が考えられます。

  • ある程度は余裕を持った大きさを確保しておいて、足りなくなれば倍 (1.5 倍程度が良いとする説もあります) に伸ばしたメモリをあらたに確保してコピー (再配置) する。 (構造が単純だが再配置のコストがまあまあ大きいという欠点がある。)
  • 要素をひとつ追加するたびにノードのメモリを確保してリンクリストとしてつなげていく。 (プログラムとしては一番簡単だと思われるが局所性に劣るのでキャッシュのヒット率が低い可能性がある。)
  • ある程度の大きさのメモリ領域 (チャンク) を単位として、足りなくなれば新しいチャンクを確保してリンクリストでつなげていく。 (上の二通りの方法の間を取った感じ。 管理が多少煩雑で面倒かも。)

投稿2020/11/07 05:03

SaitoAtsushi

総合スコア5444

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

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

0

配列で実装する場合、両者の中間の、「実際に入っているデータよりある程度大きな領域を確保する」というようなアルゴリズムが多いです。

「足りなくなったら容量を2倍に増やす」ようにしておけば、データが2倍に増えるまではコピーは起きません。

投稿2020/11/07 04:47

編集2020/11/07 04:47
maisumakun

総合スコア145183

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

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

yoshiki_iwasa

2020/11/07 04:51

ありがとうございます! なるほど、それの実装に関してググるとしたらなんて検索したらいいですかね?? 具体的に名前がついてるアルゴリズムなんでしょうか?
yumetodo

2020/11/07 04:55

libstdc++やlibc++は倍々ゲームで確保する戦略で、msvcのSTLは1.5倍を採用しているようです。
guest

0

ベストアンサー

Q:stack は 値を保持する配列はどうやって宣言しているのでしょうか?

cpprefjp - C++日本語リファレンス」によれば、デフォルトでは配列ではなく deque が使われていますね。

stack は、所定のメンバ関数を持つコンテナのオブジェクトを内部実装として用いており、標準のコンテナ、もしくは独自に実装したコンテナを指定することができる。 このコンテナに必要な要件は、以下のメンバ関数を持つことである。
back()
push_back()
pop_back()
emplace_back() (C++11)
この要件を満たすものとしては vector 、deque 、list があり、デフォルトでは deque が使用される。

投稿2020/11/07 04:46

lehshell

総合スコア1147

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

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

yoshiki_iwasa

2020/11/07 04:49 編集

あ、そうみたいですね! ありがとうございます!! 今、自分もdeque の実装を調べているところです。 もし、deque の内部挙動しってるよ〜 って人いたら教えてください m(_ _)m
yumetodo

2020/11/07 05:01 編集

dequeはシンプルに言うとstd::vector<std::array<T, N>*>です。ある程度の大きさのブロックごとに分けて管理することで要素数変化時のコピー数を減らしています。一方でデータがメモリー上で連続する保証がないので、要素アクセス速度はvectorよりも遅くなります。
lehshell

2020/11/07 05:00

イメージするのは双方向リストですが、双方向に成長する動的配列の実装もあるようです。 push() と pop() だけであれば単方向で実装すればいいのでは?
yoshiki_iwasa

2020/11/07 05:07

@yuemoto @lehshell おふたりともありがとうございます〜! ちなみに、お二人はそういった知識をどこから得ましたか?? やっぱりソースコードを読むんですかね? 書籍でも、webサイトでも参考になるソースがあったら後学のためにぜひ教えていただきたいです(^^)
yumetodo

2020/11/07 05:17 編集

自分はQiitaのC++タグがついた記事を原則全部読むとかTwitterで強い人とFF関係になることをしているのであんまり参考にならないかなと。
lehshell

2020/11/07 05:21

deque の実装に関しては規格上の規定はない認識です。不毛な話はしたくありません。 https://cpprefjp.github.io/reference/deque/deque.html には vector と同様の機能を提供するが、シーケンスの終端だけでなく先頭への効率的な挿入・削除を共に提供する。vector とは異なる欠点として deque は連続した位置のストレージに全ての要素を持つことを保証していないため、ポインタ演算を介しての安全なアクセスの可能性を排除する。 とあります。 「push() と pop() だけであれば単方向で実装すればいいのでは?」は元の stack の実装についての話です。
lehshell

2020/11/07 05:26

私は「cpprefjp - C++日本語リファレンス」と規格書ですね。Webも調べますがエビデンスの提示のないものが多い上に C や C++ は間違いも多い。
yoshiki_iwasa

2020/11/07 06:23

おふたりとも教えてくれてありがとうございました! またお願いします〜
yumetodo

2020/11/07 06:59

規格書は大事ですね。cpprefjpは私も執筆に少しですが加わってます。誤字脱字、内容のわかりにくい点ありましたらお気軽にissue/PRを立ててください。
yoshiki_iwasa

2020/11/08 03:57

@yumetodo え 書いてる側の方なんですか笑 ありがとうございます。すごい助かってます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問