C ++では、メモリ管理にプログラマーが費やす時間


39

ガベージコレクションされた言語に慣れている人は、C ++のメモリ管理が怖いことがよくあります。そこのツールは次のように、あるauto_ptrshared_ptrそれはあなたのためのメモリ管理タスクの多くを処理します。多くのC ++ライブラリはこれらのツールより前のものであり、メモリ管理タスクを処理する独自の方法があります。

メモリ管理タスクにどれくらいの時間を費やしていますか?

使用するライブラリのセットに大きく依存しているのではないかと思われるので、どのライブラリに答えが当てはまるか、それらが良くなるか悪くなるかを言ってください。


1
それほどではありません、本当に...特にC ++ 0x、リファレンス、およびSTLの場合。メモリ管理をまったく行わずにコードを書くこともできます。
コーダー

9
一般的に:あなたが経験している場合はそれほどではありません。C ++に慣れていない場合(->通常はメモリ/リソースリークのハンティング)。
MaR

1
最近では、古い参照を追いかけることについての本当の質問を見つけます。そして、それはそれは前にキャッチされなかったことだけで迷惑な、通常は毎回かなり明白です:P
マシューM.

これは古いことは知っていますが、IMOのメモリ管理は優れたプログラマーになるために不可欠な要素です。STLコンテナーのような抽象化は優れていますが、メモリーの無知は、計算自体の概念に反しています。同様に、代数的操作、ロジック、およびループをプログラマーの武器からどのように排除できるかを尋ねることもできます。
imallett

「うまくいかないメモリ管理をデバッグするのにどれくらいの時間が使われますか?」それ自体、メモリ管理は可能であり、C ++ではそれほど難しくありません。事実は、それを設定することは正確な​​技術であり、非常に失敗しやすいことです。あなたが性交するとき、あなたは気づかないかもしれません、そして、時間をかけて積み上げられた不安定な行動で古いエラーに戻って追跡することは、あなたが怖がるべきリアルタイムのシンクです。だからこそ、現代​​の非ガベージコレクション言語(私は錆のことを考えている)が、典型的なエラーをチェックする責任をコンパイラに移したのです。
ZJR

回答:


54

最新のC ++では、必要になるまで、つまり主に最適化のために、またはコンテキストによって強制される場合に(大規模な制約のあるハードウェアを考えて)手動でメモリを整理するまで、メモリ管理について心配する必要はありません。生のメモリを操作せずにゲーム全体を記述しましたが、他の言語と同様に、仕事に適したツールであるコンテナの使用のみを心配しています。

したがって、プロジェクトに依存しますが、ほとんどの場合、メモリ管理ではなく、オブジェクトのライフタイムのみを処理する必要があります。これはスマートポインターを使用して解決されますスマートポインターはRAIIに起因する慣用的なC ++ツールの1つです。

RAIIを理解すれば、メモリ管理は問題になりません。

次に、生メモリにアクセスする必要がある場合は、「どこでも」ではなく、プールオブジェクトの実装のように、非常に具体的でローカライズされた識別可能なコードでアクセスします。

この種のコード以外では、メモリを操作する必要はなく、オブジェクトの寿命だけが必要です。

「難しい」部分はRAIIを理解することです。


10
絶対に本当。過去5年間で、レガシーコードを操作するときに「削除」のみを記述しました。
drxzcl

3
スタックサイズが非常に制限された組み込み環境で作業しています。RAIIと同じくらいクールですが、スタックスペースが限られている場合はうまく機能しません。したがって、ポインターのマイクロ管理に戻ります。
バスティーブ

1
@nikie APIを操作するコードでライブラリのスマートポインターを使用してから、アプリケーションに固有のコードで標準またはブーストのスマートポインターを使用します(私が決定した場合)。アプリケーションでの使用方法を抽象化するモジュールでライブラリコードを分離できる場合、依存関係によるAPI汚染を回避できます。
クライム

12
@Paperflyer:deleteくだらない実装が1 つない限り、RAIIは手動よりも多くのスタックスペースを占有しません。
-DeadMG

2
@Paperflyer:ヒープ上のスマートポインターは同じスペースを使用します。違いは、コンパイラーが関数からのすべての出口にリソース割り振り解除コードを挿入することです。そして、これは非常に広く使用されているため、これは通常最適化されています(たとえば、複数の出口を折りたたむことはできません-後にコードを置くことはできませんreturn
-MSalters

32

メモリー管理は子供を怖がらせるために使用されますが、プログラマーが面倒を見る必要があるのはリソースの一種です。ファイルハンドル、ネットワーク接続、OSから取得するその他のリソースについて考えてください。

ガベージコレクションをサポートする言語は通常、これらのリソースの存在を無視するだけでなく、デストラクタを提供しないことでこれらを適切に処理することを難しくします。

要するに、C ++開発者の多くの時間をメモリ管理の心配に費やすことはお勧めしません。以下のようklaimの答えあなたはRAIIのハンドルを得れば、残りはちょうど反射で、示しています。


3
特にHttpWebRequest.GetResponseがGC言語で処理し、クラッシュを開始する方法が大好きです。GCは、リソースがまだリークしているために吸い始めるまでクールです。msdn.microsoft.com/en-us/library/…「注意」を参照してください
コーダー

6
メモリをリソースとして表示する場合は+1。レガシーコードであろうとなかろうと、大声で叫ぶ必要がある回数:メモリ管理はスキルであり、呪いではありません。
-aquaherd

4
@Coder私が従うかどうかわからない..とにかくリソースを悪用する可能性があるため、GCはひどい..?私は... C#はIDisposableインターを使用して解放する決定論的リソースを提供する良い仕事をして考える
マックス

8
@Max:ガベージコレクションの場合、カスタムIDisposablesを使用して愚かなリソースを心配する必要はないためです。リソースはスコープを去りました、それだけです。しかし、実際には、どれが漏れるのか、漏れないのかを考えて推測する必要があります。そもそもGC言語を使用するあらゆる理由に打ち勝ちます。
コーダー

5
@deadalnix彼らはコンストラクトを持っていfinalizeます。ただし、いつ呼び出されるかはわかりません。ソケットまたはWebResponseオブジェクトを使い果たす前ですか?信頼すべきではないfinalize-正当な理由があるという記事がたくさんあります。
災害2011年

13

ほとんどありません。COMのような古いテクノロジーでさえ、非常に短時間でそれらを変換する標準ポインター用のカスタム削除機能を作成できます。たとえばstd::unique_ptr、カスタム削除機能の5行でCOM参照を一意に保持するように変換できます。独自のリソースハンドラを手動で記述する必要がある場合でも、SRPやコピーアンドスワップなどの知識が普及しているため、リソース管理クラスを比較的簡単に記述して、いつまでも使い続けることができます。

現実には、共有、一意、および非所有権はすべてC ++ 11コンパイラに同梱されており、古いコードでも動作するように小さなアダプタを記述する必要があります。


1
a)カスタム削除ツールを作成するb)カスタム削除ツールが必要なものであることを知るために必要なC ++のスキルはどれくらい必要ですか?新しいGCで記述された言語を選択し、すべてを知らずに正確に近いものを取得するのは簡単だと思うので、C ++でも正しく取得するのは簡単ですか?
ショーンマクミラン

1
@SeanMcMillan:カスタム削除機能は簡単に記述してデプロイできます。私が言及したCOMは、すべてのCOMタイプで5行であり、最新のC ++の基本的なトレーニングを持っている人なら誰でも知っているはずです。驚いたことに、GCはCOMオブジェクトを収集しないため、GCed言語を選択することはできません。またはファイルハンドル。または、他のシステムから取得したメモリ。またはデータベース接続。RAIIはこれらすべてを行います。
-DeadMG

2
「GCされた言語を選択する」とは、Java / C#/ Ruby / Perl / Javascript / Pythonの間を行き来することを意味し、それらはすべて同じリソース管理スタイルを持っています-メモリはほとんど自動で、その他はすべて、管理する必要があります。C ++の管理ツールを使用すると、メモリと同じ方法でファイルハンドル/ db接続などを管理でき、学習すれば比較的簡単だと言っているように思えます。脳手術ではありません。正しく理解できますか?
ショーンマクミラン

3
@SeanMcMillan:はい、それはまさにその通りで、複雑ではありません。
-DeadMG

11

私がC ++プログラマーだった頃(ずっと前)、バグを再現するのが難しいのを修正しようとすると、メモリ管理のバグについて長い間心配していました

モデムC ++を使用すると、メモリ管理の問題ははるかに少なくなりますが、大規模なチームの全員が正しく管理できると信頼できます。費用/時間は何ですか:

  • トレーニング(多くのプログラマーが問題をよく理解していない)
  • メモリ管理の問題を見つけるためのコードレビュー
  • メモリ管理の問題のデバッグ
  • アプリの一部のバグは、アプリ無関係な部分のメモリ管理の問題が原因である可能性があることに常に留意する必要があります

そのため、「実行」に費やす時間だけでなく、これは大規模プロジェクトの問題です。


2
一部のC ++プロジェクトは、コードの記述が不適切であるためにメモリリークの一部を修正することに絶望していると思います。不正なコードが発生する可能性があり、その場合、他の人の時間も多くかかる可能性があります。
ジェレミー

@ Jeremy、C ++からC#に移行したとき、コードの書き方は(それ以上ではないにしても)まだありましたが、少なくとも特定のバグがあった部分を見つけるのは簡単でした。
イアン

1
はい、これが多くの店がJavaまたは.NETに移行した理由の多くです。ガベージコレクションは、不良コードによる避けられない損害を軽減します。
ジェレミー

1
奇妙なことに、これらの問題はありません。
デヴィッドソーンリー

1
@DavidThornley、多くの問題はC ++でUIコードを書くことによるものだと思います。最近見たほとんどのC ++コードはUIではありません
イアン

2

ブーストライブラリとTR1ライブラリをよく使用しますが、厳密な意味でのメモリ管理(新規/削除)は問題になりません。一方、C ++でのメモリ割り当ては安価ではなく、これらの派手な共有ポインターが作成される場所に注意する必要があります。最終的には、ワークスペースを頻繁に使用するか、スタックベースのメモリを操作します。一般に、私はそれが主に設計上の問題であり、実装上の問題ではないと言うでしょう。


2

クライアントとしてどれくらい時間がかかりますか?ほんの少しです コンテナがライフタイムと参照を管理するとき、それは非常に簡単です。imo、手動の参照カウントよりもはるかに簡単であり、使用するコンテナをドキュメントとして考慮すると、コンパイラが適切に設計されたタイプセーフシステムで無効な所有権移転を実行するのを便利に防止するため、実質的に透過的です。

(クライアントとして)私が費やす時間のほとんどは、他のAPIからの型を含むために費やされるため、プログラムのコンテキスト内でうまく機能します。例:これは私のThirdPartyFontコンテナーであり、これらの機能をサポートし、この方法で破壊を実装し、この方法で参照をカウントし、この方法でコピーし、そして...を実装します。これらの構造の多くは適切な場所に配置する必要があり、多くの場合、それらを配置する論理的な場所です。それを時間として含めるかどうかはあなたの定義に依存します(とにかく、これらのapiとインターフェースをとるときに実装が存在する必要がありますか?)。

その後、メモリと所有権を考慮する必要があります。下位レベルのシステムでは、それは適切で必要ですが、物事をどのように移動させるかを実装するには、ある程度の時間と足場が必要です。これは低レベルのシステムの要件なので、私はそれを苦痛とは思わない。所有権、管理、責任が明らかです。

したがって、不透明型を使用するCベースのAPIに向けることができます:コンテナを使用すると、これらの不透明型のライフタイムの管理とコピーの小さな実装の詳細をすべて抽象化でき、最終的にリソース管理が非常に簡単になり、時間、欠陥、実装を削減します。

これらを使用するのは非常に簡単です-問題(GCから来る)は、リソースの寿命を考慮する必要があることです。間違えた場合、解決に時間がかかることがあります。明示的なライフタイム管理の学習と統合は、(すべての人ではなく)比較すると理解しやすいほど複雑です。これが本当のハードルです。ライフタイムの制御と適切なソリューションの使用に慣れたら、リソースのライフタイムを管理するのは非常に簡単です。それは私の一日の重要な部分ではありません(難しいバグが入り込んでいない限り)。

コンテナ(自動/共有ポインタ)を使用していない場合は、苦痛を訴えているだけです。

私は自分のライブラリを実装しました。それらを実装するには時間がかかりますが、ほとんどの人は再利用します(通常は良い考えです)。


1

あなたは手動でメモリを解放し、ファイルを閉じなければならないようなものですか?そうだとすれば、特に「メモリ管理」だけでなく「リソース管理」にそれを一般化した場合、私が使用した他のほとんどの言語よりも少なく、通常は少ないと言えます。その意味で、実際には、C ++はJavaやC#よりも手動のリソース管理が少なくて済むと思います。

これは主に、リソース(メモリなど)の破壊を自動化するデストラクタが原因です。通常、C ++でリソースを手動で解放/破棄する必要があるのは、vlowレベルのデータ構造(ほとんどの人が行う必要のないもの)を実装している場合、または少し時間を費やしているC APIを使用している場合のみです手動で解放/破棄/クローズする必要があるCリソースをRAII準拠のC ++ラッパーにラップします。

もちろん、ユーザーが画像編集ソフトウェアで画像を閉じるように要求した場合、コレクションなどから画像を削除する必要があります。しかし、このコンテキストで重要な種類の「メモリ」または「リソース」管理としてカウントされないことを願っています。その時点でそのイメージに関連付けられているメモリを解放する場合、それはほとんどの言語で必要です。ただし、コレクションから画像を削除するだけで、残りは画像デストラクタが処理します。

一方、たとえばJavaやC#と比較すると、そこでファイルを手動で閉じたり、ソケットを手動で切断したり、オブジェクト参照をnullに設定してガベージコレクションできるようにしなければならないことがよくあります。これらの言語でのリソース管理。C ++ではunlock、ミューテックスがスコープ外になると、ミューテックスロッカーが自動的にミューテックスを行うため、手動でミューテックスを使用する必要さえありません。たとえば、C ++で次のようなことを行う必要はありません。

System.IO.StreamReader file = new System.IO.StreamReader(path);
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    ...
}
finally
{
    if (file != null)
        file.Close();
}

C ++でファイルを手動で閉じるようなことをする必要はありません。結果としてスコープ外に出た場合でも、通常の実行パスまたは例外的な実行パスの場合でも、スコープから出た瞬間に自動的に閉じます。のようなメモリ関連リソースについても同様ですstd::vectorfile.Close()上記のようなコードは、特にfinallyブロックのコンテキストでは、C ++に関する考え方全体がそれを自動化するときに手動でローカルリソースを解放する必要があることを示唆しているため、しばしば眉をひそめます。

手動のメモリ管理に関しては、Cが最大、Java / C#が中程度、C ++が最小のいずれかを必要とすると思います。C ++を習得するのは非常に難しい言語なので、C ++を使用することに少し恥ずかしがる理由はたくさんありますが、メモリ管理はその1つではありません。それどころか、私は実際、この一面で最も簡単な言語の1つだと思います。

もちろん、C ++を使用すると、手動でメモリを割り当てoperator delete/delete[]、手動でメモリを解放することができます。また、あなたは次のようにC関数を使用することができますmallocし、free。しかし、それは、人々が信用を与えるずっと前に時代遅れになったと思う種類の古代スタイルのコーディング慣行です。ですから、「モダンC ++」がリソース管理を自動化すると言うのはフェアではないと思います。そうしないと、例外安全性を実際に取得できません。90年代前半の多くの見当違いの開発者が、オブジェクトのあるCのようにC ++を使用しようとし、多くの場合例外処理を完全に無視し、そのように使用されることはありませんでした。実際に常に使用することを意図した方法でC ++を使用する場合、メモリ管理は完全に自動化され、通常は手動で処理する必要のある(または処理する必要のある)ことはほとんどありません。


1
最新のJavaには、「リソースで試す」機能があり、finallyブロック内の厄介なコードをすべて削除します。最終的にブロックする必要はほとんどありません。デザイナーがRAIIコンセプトをコピーしたようです。
キウィロン

0

チームのシニアテクニカルリードに依存します。一部の企業(鉱山を含む)では、スマートポイナーという概念はありません。それは派手と見なされます。そのため、人々は単に削除をあらゆる場所に配置し、2か月ごとにメモリリークを修正するためのドライブがあります。削除ステートメントの新しい波が至る所に到着します。ですから、会社とそこで働く人々の種類に依存します。


1
あなたの環境には、あなたauto_ptrや友人の使用を妨げる何かがありますか?
ショーンマクミラン

2
あなたの会社のような音は、C ++コードを書いていない、あなたはCを書いている
gbjbaanb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.