16

これはインタビューの質問です。インタビューは行われました。

C++ が C よりも遅くなる原因は何ですか?

インタビュアーはとても深く質問し、私が何かを言うたびに「他に何かありますか?」と尋ねました。

私のアイデア:

C で使用できない C++ 機能には、多少のコストがかかる場合があります。

たとえば、割り当てを使用して、初期化リストではなくコンストラクター内でクラスのメンバーを初期化する場合、メンバーの既定のコンストラクターがコンストラクターの本体の前に 1 回呼び出され、その値が割り当てによって消去される可能性があります。

仮想関数は、仮想関数ポインタを検索して呼び出す必要があります。これはオーバーヘッドです。

より良いアイデアはありますか?

どんな助けでも大歓迎です。

ありがとう !!!

4

7 に答える 7

27

C++ が C と比べて本質的に遅いということはありませんが、慣用的な C++ コードは、同じタスクを実行する慣用的な C コードよりもはるかに遅く、重くなる傾向があります。ここでは慣用的な言葉が重要です。C++ でタスクを実行する場合とまったく同じ方法でタスクを実行する C コードを作成すると、同じように遅くなります。一方、隠れたコストが一般的に C++ で忍び寄る場所を認識している場合は、コストを最小限に抑え、多くのコストをかけずに C++ の利点を得る努力をすることができます。

何よりもまず、動的メモリ割り当てです。C では、すべて明示的であるため (またはmallocまたは、割り当てられたオブジェクトを返すサードパーティ ライブラリ関数の呼び出し)。C++ では、オブジェクトのストレージ期間が自動である多くのクラス オブジェクトでは、コンストラクターで非表示の割り当てが行われるため、依然として動的メモリ割り当てが発生します。優れた C++ STL (またはサードパーティ ライブラリ) の実装では、オブジェクト自体の内部に小さなバッファーを含め、大きなバッファーが必要な場合にのみ動的割り当てを実行することで、このコストの多くを回避できますが、実際にこれを行うものはほとんどありません。(私が間違っていなければ、llvm の libc++ はそうしますが、GCC の libstdc++ はそうではありません。) これは実装の品質の問題であり、多くの場合、独自のコードでは制御できないため、影響を最小限に抑えるためにここでできる主なことは次のとおりです。自動オブジェクトが動的メモリを割り当てる可能性を認識し、また、必要以上に作成しないようにします (たとえば、可能な場合はポインターや参照を使用します)。これには、コードに対する他の利点もあります。

もう 1 つの大きな領域は、文字列の処理です。snprintf慣用的な C では、文字列は、または類似のものを使用して一挙に構築されます。C++ およびより強力な文字列クラス/型を持つ他の多くの言語では、文字列の連結 (ピースごとの構築) は慣用的です。これは非常に非効率的であり、メモリの断片化は言うまでもなく、複数の割り当て/割り当て解除手順、コピーなどにつながります。C++ のベスト プラクティスがどのようなものかはわかりませんが (私は C++ に精通していません)、この影響を最小限に抑える方法はあるはずです。

そしてもちろん、最も一般的なのは隠しコードです。これは一種のキャッチオールです。C++ では、見たことのない多くの余分なコードが実行されるコードを簡単に記述できます。コンストラクタ/デストラクタ、オーバーロードされた演算子、およびテンプレートが最も明白な原因です。繰り返しになりますが、C で同じ方法を実行したい場合、コストは同じになりますが、違いは、C では自分で作成する必要があるため、すぐにコストが表示されることです。

于 2012-05-27T18:26:47.470 に答える
14

何もない。実際、C++ は C よりも高速std::sortですqsort

仮想関数は呼び出すのに時間がかかると言われています。彼らはそうします。しかし、vtable でのルックアップに相当する C も同様です。両方の言語で同等のロジックを記述した場合、C++ バージョンの方が保守しやすく、クリーンで高速です。

編集: そうそう、必要に応じprintfて C++ から呼び出すことも、必要に応じてストリームの実装を完全にやり直すこともできます。

また、NULL ターミネータの配置ミスによってクラッシュするプログラムのパフォーマンスは、ほとんど重要ではないと言いましたか?

マクロとインライン関数は、C++ のテンプレートと同じくらい確実に C 実行可能ファイルを「膨張」させます。

于 2012-05-27T15:27:52.893 に答える
7

うわー...回答でC ++が大好きなので、Devil's Advocateとして少し怒鳴ります。

アトミック言語の規模では、C++ での実行が本質的に大幅に「遅い」ものはほとんどないか、まったくないことに同意します。より高いレベルでは、複雑になります。C++ は便利なツールですが、すべての問題の解決策として不適切に主張されているパナッシュであることがよくあります。最も単純な言語を使用して問題を記述した方がよいでしょう。C++ を使用する場合もあれば、アセンブリ、オペコード、解釈された言語を使用する場合もあります。

C++ は、意図を「解釈」するためにコンパイラに大きく依存し、テンプレート、クラス、マクロなどの多くの層を何度も反復してクロールします。翻訳のループごとに、意図しない結果の法則に遭遇する可能性があります。私の知る限り、プロセッサには、C++ が持つ構造をネイティブに処理するレジスタやオペコードがないため、それぞれを単純化された部分に分解する必要があります。この分野では、コンパイラとコード標準が重要です。場合によっては、数学の博士号を持つ教師 (コンパイラ) が 3 年生 (プロセッサ) を教えるのと哲学的に同等です。

私は C++ が好きで、保守的に使用していますが、長年にわたって適切に記述されたものはほとんど見たことがありません。ビルドによって最終的に逆流したアセンブリまたはマシン コードを、それがどれほど複雑であるかを理解するまで、一部の人に見てもらいたいと思います。悪い C は 1 つのことですが、悪い C++ は指数関数的に悪化する可能性があります。

インタビューに対するより適切な答えは... 「あなたのチームが C++ を問題の解決策ではないと考えるのはどのような場合ですか?」

于 2012-05-27T21:04:21.377 に答える
5

より良いアイデアはありますか?どんな助けでも大歓迎です。

C++ の STL 自体は、C で特別にコード化された相当するものよりも遅いことはめったにありません。ただし、STL の利便性により、より遅いコードを記述する場合があります。たとえば、100 個の項目の固定セットがあり、そこから 10 個または 15 個の可変選択が行われるとします。プログラムのタイムクリティカルなループが、項目iが選択されているかどうかを何度も尋ねるとします。このようなタイム クリティカルなループをサポートする高速データ構造は、100 個の bool の配列 (またはベクトルなど) になります。ただし、std::set<size_t>C++ では、配列にデータを入力するよりもデータを入力するほうが簡単な場合があります。この理由から、C++ プログラマーは配列よりもセットを好むかもしれません。

もちろん、遅いコードが問題になるかどうかは、タイム クリティカルなループがどれだけのサービスを受けるかによって異なります。配列手法をプログラミングするのにさらに 30 分かかり、プログラムの存続期間中の総実行時間の節約が 0.5 秒である場合、set 手法がおそらく望ましいでしょう。一方、合計実行時間の節約が 30 日である場合は、配列手法が適している可能性があります。

これらの線に沿って、多くの同様の答えが与えられる可能性があります。面接頑張ってください。

于 2012-05-27T15:44:58.533 に答える
5

C++ のほとんどの機能は、C の (潜在的な) 問題を解決するためのソリューションです (例: 作成されたデータ バンドル ( structC で) の有効性を保証するコンストラクター)

これは、C++ 機能がある問題を回避しようとする正しいプログラムを C で作成するには、C++ が舞台裏で行っているのと同様のアクションを実行する必要があることを意味します。これにより、どちらの場合も同様のパフォーマンスが得られます。

もちろん、「より速い」ずさんなプログラムを書くことはいつでもできますが、すべての場合に正しく動作するとは限りません。

于 2012-05-27T15:30:10.317 に答える
4

C には がありますがrestrict、C++ にはありませんが、ほとんどのコンパイラには拡張機能として含まれています。

C++ にはない可変長配列もあります。

于 2012-05-27T15:31:28.277 に答える
2

アプリオリにパフォーマンスの問題ではありませんが、LLVM コードベースは RTTI も例外も使用しません。これは、コード サイズの点でコストがかかりすぎると考えられているためです。

于 2012-05-27T18:05:50.697 に答える