22

C ++標準では、スタックやヒープについては何も言及されていません。これらは実装固有であり、これは事実です。

それらはC++標準の一部ではありませんが、とにかくそれらを使用することになります。そのため、それらは言語自体の一部であり、メモリまたはパフォーマンスの目的で考慮する必要があります。

したがって、私の質問は、スタックとヒープを使用しないC ++の実装がありますか?

4

7 に答える 7

12

ヒープについては他の人がすでに良い答えを出しているので、それはそのままにしておきます。

一部の実装 (IBM メインフレームなど) では、ハードウェアがスタックをサポートしていないという単純な理由から、ほとんどの人が考えるようにスタックを使用しません。代わりに、関数を呼び出すと、アクティベーション レコード (つまり、ローカル、引数、およびリターン アドレス用のスペース) がヒープ (のバージョン) から割り当てられます。これらのアクティベーション レコードは、リンクされたリストに組み込まれています。

純粋に抽象的な観点から見ると、これは確かにスタックです。他のスタックと同様に、後入れ先出しセマンティクスをサポートしています。ただし、スタックと呼ぶには、かなり抽象的に見る必要があります。一緒にリンクされたメモリブロックの図を人々に見せた場合、ほとんどのプログラマーはそれをリンクされたリストとして説明するだろうと推測するのは安全だと思います. プッシュすると、「スタック感覚で使えますが、連結リストのまま」と判断する方が多いと思います。

于 2012-06-05T19:49:27.400 に答える
6

C++ 標準では、スタックまたはヒープについては何も言及されていません

実際にはそうです-それらの言葉ではなく、スタックとヒープの実装方法を指定していません。

C++03 には、次の 3 種類の変数があります。

  1. 静的保存期間を持つもの(3.7.1)。これらは、プログラムの期間中は「範囲内」です。
  2. 自動保存期間があるもの(3.7.2)。これらは、宣言されているコンテキストでのみ有効です。それらが範囲外になると、変数は破棄され、割り当てが解除されます。
  3. 動的保存期間を持つもの(3.7.3)。これらはnew式で作成され、. で破棄されdeleteます。オブジェクト自体はスコープがなく、オブジェクトの存続期間はそれらがnew編集されたコンテキストに拘束されないという意味です。もちろん、これらのオブジェクトへの即時ポインタにはスコープが設定されています。ポインターは、自動またはめったに (通常は間違って) 静的なストレージ期間です。

「スタック」と「ヒープ」は、実際には、後の 2 番目の 2 種類のオブジェクトが存在する場所です。これらは、言語要件を実現するプラットフォームに依存する実装の詳細です。

したがって、技術的にはあなたは正しいです。標準は、ヒープとスタックについて何も述べていません。しかし、実際のプラットフォームで何らかの実装を必要とするさまざまなフレーバーのストレージ期間についてかなり述べています。最近のほとんどの PC タイプのハードウェアでは、これはヒープとスタックとして実装されています。ヒープやスタックを使用せずに、さまざまな種類のストレージ期間をプラットフォームに実装できますか? 何でも可能です。可能だと思います。しかし、その実装が最終的にどのようなものになったとしても、おそらく 2 つのうちの少なくとも 1 つに似た特性を持つでしょう。

これらすべてに加えて、標準では自動保存期間と動的保存期間の両方が必要であるという考慮事項があります。これらの要件の両方を満たさない言語実装は、C++ ではありません。近いかもしれませんが、実際には C++ ではありません。

于 2012-06-05T16:39:47.683 に答える
4

小さなプログラミング環境、たとえば8K Atmel マイクロプロセッサ (現在は 32K 以上) に基づくarduino プラットフォームの場合、ヒープは実装されておらず、ライブラリによって定義された新しい演算子はありません。すべてのオブジェクトは静的に、またはスタック上に作成されます。標準ライブラリの利点は失われますが、オブジェクト指向言語を使用して非常に小さなプラットフォームをプログラミングできるようになります。たとえば、特定の出力モードまたはシリアル ポートとして構成されたピンを表すクラスを作成し、そのクラスのオブジェクトを作成します。ルーチンにピン番号を渡すのではなく、ピン番号を指定してからそのオブジェクトの関数を呼び出します。

arduino で使用する場合new、プログラムはコンパイルされますが、リンクされません。コンパイラは avr 命令セットをターゲットとする g++ であるため、真の C++ コンパイラです。独自の実装を提供することを選択した場合は、そうすることができますが、ほとんどの場合、非常に小さなフットプリントで実装を提供するコストは、利益に値しません。

于 2012-06-05T16:41:56.770 に答える
1

はい、主に Freescale や PIC などの MCU があります

2. 現在、スタックレス プロセッサが使用されています。

私たちは、アセンブリ プログラマーのようにコアを見ていません。必要な基礎が存在する限り、最低限のプログラマー モデルで満足しています。スタックはその 1 つではありません。最近、いくつかのスタックレス コアに出くわしましたが、それらの C コンパイラの開発に問題はありませんでした。

eTPU は 24 ビットの強化された時間処理ユニットで、自動車および一般的な航空エンジン制御、およびプロセス制御で使用されます。eTPU はコプロセッサかもしれませんが、完全な命令セットと完全な CPU コアを備えており、スタックレスです。これは中規模のプロセッサです。スタックレス プロセッサの C のおかげで、今夜は運転するか飛行機で家に帰ることができます。

C99 および ISO/IEC 18037 に基づく eTPU 用の C コンパイラがあります。このプロセッサで標準の C テスト スイートを実行します。

Freescale RS08 は、従来型のスタックレス MCU です。HC08/HCS08 コアを「縮小」する過程で、Freescale は CPU スタックを削除しました。RS08 のアーキテクチャについて相談しましたが、ハードウェア スタックにこだわる必要性を感じたことはありません。

私たちが相談した別のコプロセッサについて言及すると、Freescale XGate は非常にフレンドリーな ISA とプログラマのモデルを備えていますが、スタックはありません。

次に、「ほぼスタックレス」があります。Microchip PIC にはデータ スタッキングがなく、8 エントリ (拡張 14 ビット コアでは 16 エントリ) のコール リターン スタックしかありませんでした。C が PIC で使用できることを疑う人は誰もいません。

これらのパーツ、特に eTPU は、コンパイラーが使いやすく、マシン生成コードを促進するように設計されています。

他の非スタック ベースのプロセッサもあり、一部は最近作成されたもので、さまざまなアプリケーションにまたがり、独自の C コンパイラを使用しています。中~大量のスタックレス部品があります。通常、パーツにスタックがない主な理由はパフォーマンスです。

http://www.bytecraft.com/Stack_controversy

于 2018-01-16T12:58:14.267 に答える
1

これは基本的にTA氏の答えを反映しています(+1 BTW)。スタックとヒープは抽象的な概念です。

newanddelete演算子 (and関数malloc)freeは、実際には、ヒープと呼ばれる抽象化へのインターフェイスにすぎません。したがって、C++ 実装を「ヒープレス」にするように要求する場合、実際には実装でこれらのインターフェイスの使用を許可しないように要求していることになります。実装がこれらのインターフェースに常に失敗するのを妨げるものは何もないと思います。

関数の呼び出しと、呼び出しが戻った後の現在の実行の再開 (およびオプションで戻り値の取得) は、スタック抽象化へのインターフェイスです。C++ 実装を「スタックレス」にするように要求する場合、プログラムがこれらのアクションを実行できないようにすることを C++ 実装に要求していることになります。コンパイラがこの条件を課すための適合する方法は考えられません。言語は、ソース コードが関数を定義できること、および関数を呼び出すコードを定義できることを指示します。

したがって、可能なことに関する私の答えは、「スタックレス」いいえ、「ヒープレス」はいです。

于 2012-06-05T16:57:00.780 に答える
0

C++ では関数や new 演算子などの構造が定義されているため、スタックとヒープのない実装はあり得ません。関数の呼び出しにはスタックが必要であり、インスタンスの「新規作成」にはヒープが必要です。それらの実装方法はプラットフォーム間で異なる場合がありますが、考え方は同じです。インスタンス オブジェクト用のメモリ領域と、実行ポイントと呼び出し階層を追跡するための別のメモリ領域が常に必要です。

x86 (および x64) にはこれらの便利な機能 (ESP レジスターなど) があるため、コンパイラーはそれを使用します。他のプラットフォームは異なる場合がありますが、最終結果は論理的に同等です。

于 2012-06-05T16:17:31.510 に答える
0

そのような C++ 実装はないと断言しますが、それは単純に、スタックとヒープが非常に有用な抽象化であり、基本的に市場に出回っているすべてのプロセッサがそれらを非常に効率的にするためのハードウェア サポートを提供しているからです。

C++ は効率を目的としているため、C++ の実装ではそれらを利用します。さらに、C++ プログラムは通常、孤立して動作するわけではありません。それらは、プラットフォームのApplication Binary Interfaceによって定義されるプラットフォーム エコシステムに統合する必要があります。ABI は、まったく同じ理由で、C++ 実装が従わなければならないスタックおよびその他のメモリ構造を定義します。

ただし、C++ プログラムが、エキゾチックなマイクロコントローラーを使用し、オペレーティング システム (アプリケーションが OS になります!) を使用せず、スレッドやプロセスを使用しない、単純で小さい、リソースに制約のある組み込みプラットフォームを対象としていると仮定しましょう。

まず、プラットフォームが動的メモリをまったく提供しない場合があります。リンク時に定義された静的メモリのプールを操作し、独自のメモリ割り当てマネージャーを開発する必要があります ( new)。C++ では許可されており、一部の環境では実際に使用されています。

さらに、CPU は、スタックの抽象化がそれほど有用ではないため、実装する価値がないようなものである可能性があります。たとえば、SPARC のような CPU は、大量のレジスタと組み合わされたスライディングレジスタ ウィンドウ メカニズムを定義し、スタックを関数呼び出しに非効率的に使用します (スタックは、HW で既に実行されています!)。

簡単に言うと、すべての C++ 実装はスタックを使用し、ほとんどがヒープを使用しますが、その理由はプラットフォーム プロパティと強く相関しています。

于 2012-06-05T16:50:21.123 に答える