291

まず第一に、ガベージ コレクションのメリットがあるため、この質問をしているわけではありません。私がこれを質問する主な理由は、Bjarne Stroustrup が C++ にはいつかガベージ コレクタが搭載されるだろうと言ったことを知っているからです。

そうは言っても、なぜ追加されていないのですか?C++ 用のガベージ コレクタは既にいくつかあります。これは、「言うは易く行うは難し」タイプのものの 1 つにすぎませんか? それとも、追加されていない (C++ 11 では追加されない) 他の理由がありますか?

相互リンク:

明確にするために、C++ が最初に作成されたときにガベージ コレクターがなかった理由を理解しています。なぜコレクターを追加できないのか不思議です。

4

16 に答える 16

173

暗黙のガベージコレクションが追加された可能性がありますが、それは効果がありませんでした。おそらく、実装の複雑さだけでなく、人々が十分な速さで一般的なコンセンサスに到達できないことが原因です。

ビャーネ・ストロヴルプ自身からの引用:

オプションで有効にできるガベージコレクターがC++0xの一部になることを期待していましたが、そのようなコレクターが他の言語とどのように統合されるかを詳細に指定するだけで、十分な技術的問題が発生しました。 、提供されている場合。基本的にすべてのC++0x機能の場合と同様に、実験的な実装が存在します。

ここにトピックの良い議論があります。

総括:

C ++は非常に強力で、ほとんど何でもできます。このため、パフォーマンスに影響を与える可能性のある多くのことを自動的にプッシュすることはありません。ガベージコレクションは、スマートポインター(参照カウントでポインターをラップするオブジェクト。参照カウントが0に達すると自動的に削除されるオブジェクト)を使用して簡単に実装できます。

C ++は、ガベージコレクションを持たない競合他社を念頭に置いて構築されました。効率は、C++がCや他のものと比較して批判をかわさなければならなかった主な懸念でした。

ガベージコレクションには2つのタイプがあります...

明示的なガベージコレクション:

C ++ 0xには、shared_ptrで作成されたポインターを介したガベージコレクションがあります

あなたがそれを望むならあなたはそれを使うことができます、あなたがそれを望まないならあなたはそれを使うことを強制されません。

C ++ 0xより前のバージョンの場合、boost:shared_ptrが存在し、同じ目的を果たします。

暗黙のガベージコレクション:

ただし、透過的なガベージコレクションはありません。ただし、これは将来のC++仕様の焦点になります。

Tr1に暗黙のガベージコレクションがないのはなぜですか?

C ++ 0xのtr1が持つべきものはたくさんありますが、以前のインタビューでBjarne Stroustrupは、tr1には彼が望むほど多くはなかったと述べています。

于 2008-09-29T00:58:30.970 に答える
157

ここで議論に追加します。

ガベージ コレクションには既知の問題があり、それらを理解すると、C++ に問題がない理由を理解するのに役立ちます。

1.パフォーマンス?

多くの場合、最初の不満はパフォーマンスに関するものですが、ほとんどの人は自分が何について話しているのかを本当に理解していません。問題が示すようにMartin Beckett、パフォーマンス自体ではなく、パフォーマンスの予測可能性です。

現在、広く展開されている GC には 2 つのファミリがあります。

  • マークアンドスイープの種類
  • 参照カウントの種類

Mark And Sweep方が高速ですが (全体的なパフォーマンスへの影響が少ない)、「世界がフリーズする」症候群に悩まされます。つまり、GC が開始されると、GC がクリーンアップを行うまで他のすべてが停止します。数ミリ秒で応答するサーバーを構築したい場合...一部のトランザクションは期待に応えられません:)

問題Reference Countingは異なります。アトミックカウントが必要なため、特にマルチスレッド環境では、参照カウントによってオーバーヘッドが増加します。さらに、参照サイクルの問題があるため、それらのサイクルを検出して排除するための巧妙なアルゴリズムが必要です (一般的には、頻度は低くなりますが、「世界を凍結する」ことによっても実装されます)。一般に、今日の時点では、この種の (通常はより応答性が高く、むしろフリーズする頻度は低くなりますが) はMark And Sweep.

「Freeze The World」の側面がない場合Reference Countingと同様のグローバル パフォーマンスを持つガベージ コレクターを実装しようとしている Eiffel の実装者による論文を見たことがあります。Mark And SweepGC 用に別のスレッドが必要でした (標準)。アルゴリズムは(最後に)少し恐ろしいものでしたが、この論文は概念を 1 つずつ紹介し、「単純な」バージョンから本格的なバージョンへのアルゴリズムの進化を示すという点で優れていました。PDFファイルに手を戻すことができれば読むことをお勧めします...

2. リソースの取得は初期化 (RAII)

C++リソースの所有権をオブジェクト内にラップして、それらが適切に解放されるようにするという点で、これは一般的なイディオムです。ガベージコレクションがないため、主にメモリに使用されますが、他の多くの状況でも役立ちます。

  • ロック (マルチスレッド、ファイルハンドルなど)
  • 接続 (データベース、別のサーバーなどへ)

アイデアは、オブジェクトの有効期間を適切に制御することです。

  • あなたがそれを必要とする限り、それは生きているべきです
  • 使い終わったら殺すべき

GC の問題は、GC が前者に役立ち、最終的に後でそれを保証する場合...この「究極」では十分ではない可能性があることです。ロックを解除する場合は、それ以上の呼び出しがブロックされないように、すぐに解除してください。

GC を使用する言語には、次の 2 つの回避策があります。

  • スタック割り当てが十分な場合は GC を使用しないでください。通常はパフォーマンスの問題のためですが、スコープが有効期間を定義するため、このケースでは本当に役立ちます
  • using構造...しかし、それは明示的な(弱い)RAIIですが、C++ではRAIIは暗黙的であるため、ユーザーは無意識のうちにエラーを起こすことはできません(usingキーワードを省略して)

3.スマートポインター

スマート ポインターは、多くの場合、.NET でメモリを処理するための特効薬として登場しC++ます。スマート ポインターがあるので、結局 GC は必要ないという話をよく耳にします。

これ以上の間違いはありません。

スマート ポインターは役立ちます。RAII の概念auto_ptrを使用すると、非常に便利です。unique_ptrそれらは非常に単純なので、自分で簡単に書くことができます。

所有権を共有する必要がある場合、それはより困難になります。複数のスレッド間で共有する場合があり、カウントの処理にはいくつかの微妙な問題があります。したがって、自然に の方に向かいshared_ptrます。

それは素晴らしいことです。結局のところ、それがBoostの目的ですが、特効薬ではありません. 実際、主な問題shared_ptrは、によって実装されたGCをエミュレートするReference Countingことですが、サイクル検出をすべて自分で実装する必要があります... Urg

もちろんweak_ptr、これはありますが、残念ながらshared_ptr、これらのサイクルのために を使用しているにもかかわらず、メモリ リークが発生していることをすでに確認しています...そして、マルチスレッド環境にいる場合、検出するのは非常に困難です!

4. 解決策は何ですか?

特効薬はありませんが、いつものように、確実に実現可能です。GC がない場合、所有権を明確にする必要があります。

  • 可能であれば、一度に 1 人の所有者を持つことを好む
  • そうでない場合は、クラス図に所有権に関するサイクルがないことを確認し、weak_ptr

確かに、GC があれば素晴らしいことですが、それは些細な問題ではありません。それまでの間は、袖をまくり上げる必要があります。

于 2010-02-24T14:40:11.600 に答える
57

どんなタイプ?組み込み型洗濯機コントローラー、携帯電話、ワークステーション、またはスーパーコンピューター用に最適化する必要がありますか?
GUIの応答性またはサーバーの読み込みを優先する必要がありますか?
大量のメモリまたは大量のCPUを使用する必要がありますか?

C / c ++は、非常に多くの異なる状況で使用されます。ほとんどのユーザーにとって、ブーストスマートポインターのようなもので十分だと思います

編集-自動ガベージコレクターはパフォーマンスの問題ではなく(いつでもサーバーを追加購入できます)、予測可能なパフォーマンスの問題です。
GCがいつ開始されるかわからないことは、ナルコレプシーの航空会社のパイロットを雇うようなものです。ほとんどの場合、彼らは素晴らしいですが、本当に応答性が必要なときは!

于 2008-09-29T00:56:11.333 に答える
36

C++ にガベージ コレクションが組み込まれていない最大の理由の 1 つは、ガベージ コレクションをデストラクタとうまく連携させるのが非常に難しいことです。私の知る限り、それを完全に解決する方法はまだ誰も知りません。対処すべき問題はたくさんあります:

  • オブジェクトの確定的なライフタイム (参照カウントではこれが得られますが、GC では得られません。大したことではないかもしれませんが)。
  • オブジェクトがガベージ コレクションされているときにデストラクタがスローするとどうなりますか? ほとんどの言語は、この例外を無視します。これは、転送できる catch ブロックが実際には存在しないためですが、これはおそらく C++ では受け入れられる解決策ではありません。
  • 有効/無効にする方法は?当然のことながら、おそらくコンパイル時の決定になりますが、GC 用に記述されたコードと NOT GC 用に記述されたコードは非常に異なり、おそらく互換性がありません。これをどのように調和させますか?

これらは、直面している問題のほんの一部です。

于 2008-09-29T01:27:44.830 に答える
23

これは昔からの質問ですが、まだ誰も対処していない問題が 1 つあります。ガベージ コレクションを指定することはほとんど不可能です。

特に、C++ 標準は、実装がその動作を実現する方法ではなく、外部から観察可能な動作に関して言語を指定することに非常に注意を払っています。ただし、ガベージ コレクションの場合、外部から観察できる動作は事実上ありません。

ガベージ コレクションの一般的な考え方は、メモリ割り当てが確実に成功するように合理的な試みを行うことです。残念ながら、ガベージ コレクターが動作している場合でも、メモリ割り当てが成功することを保証することは本質的に不可能です。これはどのような場合でもある程度当てはまりますが、特に C++ の場合はそうです。これは、コレクション サイクル中にメモリ内のオブジェクトを移動するコピー コレクター (または同様のもの) を (おそらく) 使用できないためです。

オブジェクトを移動できない場合、割り当てを行うための単一の連続したメモリ空間を作成することはできません。つまり、ヒープ (またはフリー ストア、または任意の名前で呼びたいもの) を作成でき、おそらくそうするでしょう。 、時間の経過とともに断片化します。これにより、要求された量よりも多くの空きメモリがある場合でも、割り当てが成功しない可能性があります。

まったく同じ割り当てパターンを繰り返し繰り返し、最初に成功した場合、割り当てられたメモリが繰り返しの間にアクセスできなくなりました。それは本質的に役に立たないほど弱い保証ですが、それを強化する合理的な希望は見当たりません.

それでも、C++ に対して提案されているものよりも強力です。以前の提案[警告: PDF] (削除された) は、何も保証していませんでした。提案の 28 ページで、外部から観察可能な行動の邪魔になったのは、次のような 1 つの (非規範的な) メモでした。

[ 注: ガベージ コレクションされたプログラムの場合、ホストされた高品質の実装では、再利用する到達不能メモリの量を最大化するように試行する必要があります。—終わりのメモ]

少なくとも私にとっては、これは投資収益率について深刻な問題を引き起こします。私たちは既存のコードを壊し (正確にどれくらいかは誰にもわかりませんが、間違いなくかなりの量です)、実装に新しい要件を課し、コードに新しい制限を課します。

せいぜい、Java でのテストに基づいて、現在と同じ速度で実行するにはおそらく約 6 倍のメモリを必要とするプログラムが得られます。さらに悪いことに、ガベージ コレクションは最初から Java の一部でした -- C++ はガベージ コレクタに十分な制限を加えているため、コストと利益の比率はほぼ確実に悪化します (提案で保証されているものを超えて、あると仮定したとしても)多少の利益)。

この状況を数学的に要約すると、これは複雑な状況です。数学者なら誰でも知っているように、複素数には実数と虚数の 2 つの部分があります。ここにあるのは現実のコストですが、利益は (少なくとも大部分は) 想像上のものであるように私には思えます。

于 2011-06-13T15:54:21.607 に答える
16

自動ガベージコレクションが必要な場合は、C++用の優れた商用およびパブリックドメインのガベージコレクターがあります。ガベージコレクションが適しているアプリケーションの場合、C ++は、他のガベージコレクション言語と比べて遜色のないパフォーマンスを備えた、優れたガベージコレクション言語です。C ++での自動ガベージコレクションの説明については、C ++プログラミング言語(第4版)を参照してください。Hans-Jも参照してください。CおよびC++のガベージコレクションに関するBoehmのサイト(アーカイブ)。

また、C ++は、ガベージコレクタなしでメモリ管理を安全かつ暗黙的に行えるようにするプログラミング手法をサポートしています。ガベージコレクションは最後の選択肢であり、リソース管理の処理方法としては不完全だと思います。それは、それが決して役に立たないという意味ではなく、多くの状況でより良いアプローチがあるということだけを意味します。

出典:http ://www.stroustrup.com/bs_faq.html#garbage-collection

組み込まれていない理由については、正しく覚えていれば、GCが登場する前に発明されたものであり、いくつかの理由でこの言語にGCが含まれている可能性はないと思います(IE後方互換性C)

お役に立てれば。

于 2008-09-29T01:04:16.993 に答える
10

C ++の背後にある考え方は、使用しない機能に対してパフォーマンスへの影響を支払わないというものでした。したがって、ガベージコレクションを追加するということは、一部のプログラムをCのようにハードウェア上で直接実行し、一部のプログラムをある種のランタイム仮想マシン内で実行することを意味します。

サードパーティのガベージコレクションメカニズムにバインドされている何らかの形式のスマートポインタを使用することを妨げるものは何もありません。MicrosoftがCOMでそのようなことをしたことを思い出しているようですが、うまくいきませんでした。

于 2008-09-29T01:01:48.230 に答える
8

C ++に関するほとんどの「理由」の質問に答えるには、C++の設計と進化を読んでください。

于 2008-09-29T01:11:14.403 に答える
3

すべての技術的な話は、概念を複雑にしすぎています。

すべてのメモリに対してGCをC++に自動的に配置する場合は、Webブラウザのようなものを検討してください。Webブラウザは、完全なWebドキュメントをロードし、Webスクリプトを実行する必要があります。Webスクリプト変数をドキュメントツリーに保存できます。多くのタブが開いているブラウザのBIGドキュメントでは、GCが完全なコレクションを実行するたびに、すべてのドキュメント要素もスキャンする必要があることを意味します。

ほとんどのコンピューターでは、これはページフォールトが発生することを意味します。したがって、質問に答える主な理由は、ページフォールトが発生することです。これは、PCが大量のディスクアクセスを開始したときにわかります。これは、無効なポインタを証明するために、GCが大量のメモリにアクセスする必要があるためです。大量のメモリを使用する真正なアプリケーションを使用している場合、ページフォールトが原因で、コレクションごとにすべてのオブジェクトをスキャンする必要があります。ページフォールトとは、仮想メモリをディスクからRAMに読み戻す必要がある場合です。

したがって、正しい解決策は、アプリケーションをGCを必要とする部分と必要としない部分に分割することです。上記のWebブラウザーの例の場合、ドキュメントツリーがmallocで割り当てられていても、javascriptがGCで実行されている場合、GCが起動するたびに、メモリのごく一部とメモリのすべてのPAGEDOUT要素のみがスキャンされます。ドキュメントツリーをページに戻す必要はありません。

この問題をさらに理解するには、仮想メモリとそれがコンピュータにどのように実装されているかを調べてください。RAMがそれほど多くない場合に、プログラムで2GBを使用できるという事実がすべてです。32BItシステム用に2GBのRAMを搭載した最新のコンピューターでは、1つのプログラムのみが実行されていれば、それほど問題にはなりません。

追加の例として、すべてのオブジェクトをトレースする必要がある完全なコレクションについて考えてみます。まず、ルート経由で到達可能なすべてのオブジェクトをスキャンする必要があります。次に、手順1で表示されているすべてのオブジェクトをスキャンします。次に、待機中のデストラクタをスキャンします。次に、もう一度すべてのページに移動し、すべての非表示のオブジェクトをオフにします。これは、多くのページが何度もスワップアウトおよびスワップバックされる可能性があることを意味します。

簡単に言うと、すべてのメモリに触れた結果として発生するページフォールトの数により、プログラム内のすべてのオブジェクトの完全なGCが実行不可能になるため、プログラマーはGCをスクリプトなどの補助として表示する必要があります。およびデータベースは機能しますが、手動のメモリ管理で通常のことを行います。

そしてもちろん、他の非常に重要な理由はグローバル変数です。コレクターがグローバル変数ポインターがGCにあることを知るには、特定のキーワードが必要になるため、既存のC++コードは機能しません。

于 2011-10-23T22:42:18.107 に答える
3

C++ と Java を比較すると、C++ は暗黙的なガベージ コレクションを念頭に置いて設計されていませんでしたが、Java はそうでした。

C スタイルで任意のポインターのようなものを使用することは、GC の実装にとって悪いだけでなく、大量の C++ レガシー コードの下位互換性を損なうことにもなります。

それに加えて、C++ は、複雑なランタイム環境ではなく、スタンドアロンの実行可能ファイルとして実行することを目的とした言語です。

全体として:はい、ガベージ コレクションを C++ に追加することは可能かもしれませんが、継続性のためにそうしない方が良いでしょう。

于 2016-08-21T17:20:43.190 に答える
3

短い回答: ガベージ コレクションを効率的に (わずかな時間とスペースのオーバーヘッドで) 常に正しく (考えられるすべてのケースで) 行う方法はわかりません。

詳細な回答: C と同様に、C++ はシステム言語です。これは、オペレーティング システムなどのシステム コードを記述するときに使用されることを意味します。つまり、C++ は、C と同様に、可能な限り最高のパフォーマンスを主な目標として設計されています。言語の標準は、パフォーマンス目標を妨げる可能性のある機能を追加しません。

ここで、「なぜガベージ コレクションがパフォーマンスを妨げるのか?」という疑問を一時停止します。主な理由は、実装に関して言えば、私たち [コンピューター科学者] は、すべての場合において最小限のオーバーヘッドでガベージ コレクションを行う方法を知らないためです。したがって、C++ コンパイラとランタイム システムがガベージ コレクションを常に効率的に実行することは不可能です。一方、C++ プログラマーは、自分の設計/実装を知っている必要があり、ガベージ コレクションを最適に行う方法を決定するのに最適な人物です。

最後に、制御 (ハードウェア、詳細など) とパフォーマンス (時間、スペース、電力など) が主な制約でない場合、C++ は書き込みツールではありません。他の言語の方が適切に機能し、より多くの [隠された] ランタイム管理を提供し、必要なオーバーヘッドが発生する可能性があります。

于 2012-11-18T20:58:20.727 に答える