C ++の最悪の慣行、よくある間違い[終了]


35

Linus Torvaldsによるこの有名な暴言を読んだ後、私は実際にC ++のプログラマーにとっての落とし穴は何なのか疑問に思いました。私はこの質問とその回答で扱われているタイプミスや悪いプログラムフローを明示的に言及していませんが、コンパイラによって検出されず、最初の実行時に明らかなバグ、完全な設計エラーを引き起こさないより高レベルのエラー、 Cではありえないが、コードの完全な意味を理解していない新参者がC ++で行う可能性が高いこと。

また、通常は予想されないパフォーマンスの大幅な低下を指摘する回答も歓迎します。私が書いたLR(1)パーサージェネレーターについて、ある教授が私に言ったことの例:

不要な継承と仮想性のインスタンスを使用しすぎています。継承は設計をより複雑にし(RTTI(実行時型推論)サブシステムのために非効率的です)、したがって、たとえば解析テーブルのアクションなど、理にかなっている場合にのみ使用する必要があります。テンプレートを集中的に使用するため、実質的に継承は必要ありません。」


6
C / C ++で発生する可能性のあるより厄介なエラーのいくつかは、主にCの遺産によるものです...未定義の動作、手動のメモリ管理などを読んでください。また、教授のアドバイスは偽りです/間違っていますC ++のエキスパート)-テンプレートのインスタンス化は、virtual関数のvtableを持つ通常のクラスを生成するはずですよね?

8
あなたは教授が言ったことを誤って覚えているか、彼が何について話しているのか見当がつかなかった。派生クラスでは、一般にRTTI(別名リフレクション)を使用して物事を調べる必要はありません。仮想メソッドを使用している場合、コードはディスパッチに対してvtableルックアップを実行する必要がありますが、これは多くのプロセッサで単一のASM命令に変換されます。キャッシングの問題により、一定量だけ処理が遅くなる可能性がありますが、最も要求の厳しいユースケース以外のオーバーヘッドに気付くことはほとんどありません。C ++を避ける理由はたくさんありますが、vtableルックアップはそれらの1つではありません。
メイソンウィーラー

5
@FelixDombek:非常に一般的に述べられ、全面的に適用されているので、教授からの引用は膨大な量の無知を示​​しています。設計に何らかのランタイムポリモーフィズムが必要な場合、多くの場合、仮想関数を使用することが最良の選択です。不要な場合は使用しないでください。たとえば、派生クラスを使用するからといって、すべてのメソッドを仮想にする必要はありません。
フレッドナーク

5
@Mason Wheeler:RTTIには型に関する情報が含まれており、a dynamic_castが成功するかどうかを判断するのに十分であり、他にはほとんどありませんが、メンバー属性または関数に関する情報を取得できるなど、リフレクションはさらに多くをカバーしますC ++に存在します。
デビッド・ロドリゲス-ドリベス

5
継承と仮想関数はパフォーマンスに大きな影響を与えないため、教授のコメントはやや欺いています。継承を控えめに使用することは良いアドバイスですが、効率よりもプログラム構造の問題です。継承は、特に保護されたメンバーの場合、取得するカップリングとほぼ同じであり、必要ない場合は使用しないでください。
デビッドソーンリー

回答:


69

トーバルズはここで彼のお尻について話しています。


OK、なぜ彼はお尻から話しているのですか:

まず第一に、彼の暴言は本当に何もないが、暴言ではない。ここには実際のコンテンツはほとんどありません。それが本当に有名であるか、やや尊敬されている唯一の理由は、それがLinuxの神によって作られたからです。彼の主な主張は、C ++はがらくたであり、C ++の人々を怒らせるのが好きだということです。もちろん、それに答える理由はまったくなく、それを合理的な議論だと考える人は、とにかく会話を超えています。

彼の最も客観的なポイントとして光り輝くものに関しては:

  • STLとBoostはまったくのくだらない<-何でも。あんたってほんとバカ。
  • STLとブーストは無限の痛みを引き起こす<-とんでもない。明らかに彼は過度に過大評価しているが、ここで彼の本当の声明は何ですか?知りません。Spiritなどでコンパイラーの嘔吐を引き起こした場合、問題を理解するのは非常に困難ですが、void *のようなC構造の誤用によって引き起こされるUBのデバッグよりも理解することは多かれ少なかれ難しくありません。
  • C ++が推奨する抽象モデルは非効率的です。<-なに?彼は決して拡大せず、彼が何を意味するかの例を提供しません、彼はそれを言うだけです。BFD。彼が何を言っているのかわからないので、声明を「反論」しようとすることはほとんど意味がありません。これはCの偏屈者の一般的なマントラですが、それがそれを理解しやすくしたり、わかりやすくしたりすることはありません。
  • C ++を正しく使用するということは、Cの側面に限定することを意味します。<-実際、そこにあるWORSE C ++コードはこれを行っているので、彼が話しているWTFがまだわかりません。

基本的に、トーバルズは彼のお尻から話しています。何についても理解できる議論はありません。そのようなナンセンスの深刻な反論を期待することは、単なる愚かなことです。私はそれを言った私がどこでそれを展開することが期待される何かの反論で「展開」するようになっています。本当に、トーバルズが言ったことを正直に見てみると、彼は実際には何も言わなかったことがわかるでしょう。

神が言っているからといって、それが意味をなさないか、またはランダムなボゾがそれを言った場合よりも真剣に受け止められるべきだという意味ではありません。真実は言われます、神は単なる別のランダムなボゾです。


実際の質問への回答:

おそらく最悪の、そして最も一般的な、悪いC ++プラクティスは、それをCのように扱うことです。printf、gets(Cでも悪いと考えられます)、strtokなどのC API関数の継続使用は、提供されるパワーを活用できないだけではありませんより厳密な型システムにより、「実際の」C ++コードと対話しようとすると、必然的にさらに複雑になります。したがって、基本的には、Torvaldsがアドバイスしていることとは正反対のことをしてください。

STLとBoostを活用して、バグのコンパイル時間をさらに検出し、他の一般的な方法で生活を楽にする方法を学習します(たとえば、boostトークナイザーはタイプセーフであり、より良いインターフェイスです)。テンプレートエラーの読み方を学ぶ必要があるのは事実ですが、最初は気が遠くなりますが、(とにかく私の経験では)実行時に未定義の動作を生成するものをデバッグするよりもはるかに簡単です。とても簡単です。

Cがそれほど良くないというわけではありません。もちろん、C ++の方が好きです。Cを好むCプログラマー。プレイにはトレードオフと主観的な好みがあります。また、多くの誤った情報とFUDが流れています。私はC ++の周りにもっと多くのFUDと誤った情報が浮かんでいると言うでしょうが、私はこの点で偏っています。たとえば、C ++が持つと思われる「肥大化」および「パフォーマンス」の問題は、実際にはほとんどの場合、実際には大きな問題ではなく、現実のプロポーションから吹き飛ばされます。

教授が言及している問題に関しては、これらはC ++に固有のものではありません。OOP(および汎用プログラミング)では、継承よりも合成を優先します。継承は、すべてのオブジェクト指向言語に存在する可能な限り強力な結合関係です。C ++は、さらに強力な友情を追加します。ポリモーフィックな継承は、抽象化と「is-a」関係を表すために使用する必要があり、再利用には決して使用しないでください。これは、C ++で犯すことができる2番目に大きな間違いであり、非常に大きな間違いですが、言語固有のものとはほど遠いものです。C#またはJavaでも非常に複雑な継承関係を作成できますが、それらにはまったく同じ問題があります。


1
皮肉なことに、2007年以降、gitは移植可能なバージョンのLinuxのみを実行していました。まあ、Unixに類似したシステム。繰り返しますが、gitの作成につながった状況を考えると、私は確かにgitを保持しません。
クリスK

9
Linusは、彼のために働きたい優秀なC ++プログラマを見つけるのに苦労しています。なぜだろう?これは鶏と卵のタイプの問題だと思います。
ボーパーソン

19

私は、C ++の危険性は、経験の浅いC with Classesプログラマーによって非常に誇張されていると常に考えてきました。

はい、C ++はJavaのようなものよりも入手しにくいですが、最新の手法を使用してプログラミングする場合、堅牢なプログラムを作成するのは非常に簡単です。私は正直ありませんよう、私は、Javaのような言語で行うよりもC ++での時間のプログラミングの多くがより困難、と私はよく、私は他の言語で設計するとき、自分が特定のC ++テンプレートやRAIIのような抽象化を行方不明見つけます。

そうは言っても、C ++での長年のプログラミングの後でも、ときどき、高レベルの言語では不可能な、本当にばかげた間違いを犯します。C ++の一般的な落とし穴の1つは、オブジェクトの有効期間を無視することです。JavaとC#では、すべてのオブジェクトがヒープ上に存在し、魔法のガベージコレクターによって管理されるため、通常、オブジェクトの有効期間*を気にする必要はありません。

現在、現代のC ++では、通常、オブジェクトのライフタイムについてもあまり気にする必要はありません。オブジェクトの存続期間を管理するデストラクタとスマートポインタがあります。99%の時間、これは見事に機能します。しかし、ときどき、ぶら下がりポインター(または参照)にねじ込まれます。たとえば、最近Foo、別のオブジェクトへの内部参照変数を含む(呼び出しましょうBar)オブジェクトがありました(呼び出しましょう)。ある時点で、私は愚かにも物事を整理して、それBarが以前に範囲外になったがFooFooデストラクタがのメンバー関数を呼び出すことになったBar。言うまでもなく、物事はうまくいきませんでした。

今、私はこれをC ++のせいにすることはできません。それは私自身の悪い設計でしたが、ポイントは、この種のことは高レベルのマネージド言語では起こらないということです。スマートポインターなどを使用しても、オブジェクトのライフタイムを認識する必要がある場合があります。


*管理対象のリソースがメモリの場合、つまり。


8
JavaとC#でオブジェクトの寿命を気にする必要はありませんか?GCはメモリを処理しますが、それは私にとってRAIIのほんの一部です。たとえば、これらの言語が持つさまざまな「使い捨て」インターフェースを見てください。
フレッドナーク

Javaでは、I / Oライブラリの設計が不便であることを除いて、オブジェクトの寿命を気にする必要はほとんどありません。
dan04

あなたのぶら下がり参照問題は、私が解決しようとしているものです。私は自分のブログでそれを解決する方向について議論を始めました(ポインターの約束)。基本的に、この言語ではさらにいくつかのスマートポインターを使用できると思います。興味があれば、その議論に参加してください。他に誰もそんなことはしていません...しかし、それがあなたが解決したいと思う何かであるならば...私は実際に10%以上の時間に問題に実際に出くわします。
エドワードストレンジ

13

通常、コードの違いは、言語よりもプログラマに関連しています。特に、優れたC ++プログラマーとCプログラマーは、どちらも(たとえ異なっていても)同様に優れたソリューションになります。現在、Cは(言語としての)より単純な言語であり、コードが実際に行うことに対する抽象化が少なく、可視性が高いことを意味します。

彼の暴言の一部(彼はC ++に対する暴言で知られています)は、より多くの人々がC ++に取り組み、いくつかの抽象化が隠して間違った仮定をすることを実際に理解せずにコードを書くという事実に基づいています。


3
std::vector<bool>各値の変更を反復するコストはいくらですか?for ( std::vector<bool>::iterator it = v.begin(), end = v.end(); it != end; ++it ) { *it = !*it; }?抽象化されたものは何*it = !*it;ですか?
デビッド・ロドリゲス-ドリベス

2
...広くミスと批判特定の言語の憎悪に迎えに不公平かもしれませんが
フレッドNurk

2
@Fred Nurk:std::vector<bool>よく知られている間違いですが、議論されていることの実に良い例です。抽象化は優れていますが、隠れているものには注意する必要があります。ユーザーコードでも同じことが起こり得ます。まず、C ++とJavaの両方で例外を使用してフロー制御を実行し、実際に救済例外ランチャーであるネスト関数呼び出しのように見えるコードをvoid endOperation();実装しましたthrow EndOperation;。優れたプログラマーは、これらの驚くべき構造を避けますが、実際には、それらを見つけることができます。
デヴィッドロドリゲス-ドリベス

5
Torvaldsのポイントの1つは、C ++よりもCを選択するだけで初心者を追い払うことができ(C ++初心者が多いようです)、C ++がより複雑になると学習曲線が急になり、コーナーケースでトリップする可能性が高くなることです。
デビッドロドリゲス-ドリベス

2
+1、これはまさにLinusが不満を言っていることです。彼はアンチC ++であるように見えますが、そうではありません。彼は唯一のアンチC ++プログラマーです。
greyfade

13

try/catchブロックの過剰使用。

File file("some.txt");
try
{
  /**/

  file.close();
}
catch(std::exception const& e)
{
  file.close();
}

これは通常、Javaのような言語に由来し、人々はC ++にはfinalize句がないと主張します。

ただし、このコードには2つの問題があります。

  • 実際にに存在しないファイルを作成fileするtry/catchことはできないため、の前にビルドする必要がありcloseますcatch。これは、file閉じた後に表示される「スコープリーク」につながります。ブロックを追加できますが...:/
  • 誰かが来returntryスコープの真ん中にaを追加した場合、ファイルは閉じられません(だから人々はfinalize条項の欠如について悩んでいます)

ただし、C ++では、この問題に対処するためのはるかに効率的な方法があります。

  • Javaの finalize
  • C# using
  • 行く defer

RAIIがあり、その興味深い特性はSBRM(Scoped Bound Resources Management)と最もよく要約されています。

デストラクタが所有するリソースをクリーンアップするようにクラスを作成することにより、すべてのユーザーのリソースを管理する責任を負いません!

これは他の言語では見逃している機能であり、おそらく最も忘れられている機能です。

真実は、try/catchロギングなしで終了を回避するために、トップレベルを別にして、C ++でブロックを記述する必要さえほとんどないということです。


1
私はそれは(あなたが直接置き換えることができ、それのC.限りのJavaの影響はないと思うfopenし、fcloseここに。)RAIIがここで物事を行うには「正しい」方法ですが、CからCライブラリを使用したい人のためのそれの不便++ 。
dan04

このタイプの回答では、正しいソリューションの例を提供することが適切です。
クラウスヨルゲンセン14年

@ClausJørgensen:残念ながら、ソリューションは本当に「派手」ではありません。なぜなら、それはただそれだけだFile file("some.txt");からです(いいえopen、いいえclose、いいえtry...)
Matthieu M. 14年

DにはRAIIもあります
デミ

@Demetri:私はDにあまり詳しくありませんが、RAIIがガベージコレクションとどのように相互作用するかを説明してもらえますか?Pythonで「deinit」メソッドを記述できることは知っていますが、ドキュメントでは、参照のサイクルの場合、一部のオブジェクトではdeinitメソッドが呼び出されないことが警告されています。
マチューM. 14年

9

条件に適合する一般的なエラーの1つは、クラスで割り当てられたメモリを処理するときにコピーコンストラクターがどのように機能するかを理解していないことです。「noob」がオブジェクトをマップまたはベクターに配置し、コピーコンストラクターとデストラクターを適切に記述しなかったため、クラッシュやメモリリークの修正に費やした時間のカウントを失いました。

残念ながら、C ++にはこのような「隠れた」落とし穴がたくさんあります。しかし、それについて不平を言うのは、あなたがフランスに行って、人々が何を言っているのか理解できなかったという不満のようなものです。あなたがそこに行くつもりなら、言語を学んでください。


1
C ++の問題は、自分自身を非常に簡単に撃つことができると思う。確かに、C ++で書かれた優れたソフトウェアがたくさんあります。しかし、優れたC ++開発者になるのは非常に困難です。Scott Meyersの「Efficient C ++」シリーズは、この言語の繊細さを示しています。
マルコムスタピック

同意する。しかし、問題の一部は、多くの(大多数の)C ++プログラマーが、明らかにしていないときに自分が何をしているのかを知っていると考えることです。「効果的なC ++」という意味ですか?
ヘンリー

少なくともこれは、C ++ 0xでのコピー/移動操作の暗黙的な生成に関する新しいかなり制限されたルールで改善されています。3つのルールに違反するケースの多くでは、コピー操作の暗黙的な生成は非推奨になり、警告が生成されるはずです。
セリビッツ

6

C ++ では、さまざまな機能とプログラミングスタイルを使用できますが、これらが実際にC ++を使用する良い方法であることを意味するわけではありません。実際、C ++を誤って使用するのは信じられないほど簡単です。

適切に学習し、理解する必要があります。実行(または他の言語を使用するように使用)するだけで学習すると、非効率でエラーが発生しやすいコードになります。


4

まあ...まず、読むことができます C ++ FAQ Liteを

その後、何人かの人々がC ++の複雑さに関する本を書くキャリアを築きました。

ハーブサッタースコット・マイヤーズ

トーバルズの暴言については、実質的に...人々に真剣に来てください:言語のニュアンスを扱う上でそれほど多くのインクがこぼれた言語は他にありません。Python、Ruby、Javaの本はすべて、アプリケーションの作成に焦点を当てています。C++の本は、愚かな言語の機能/ヒント/トラップに焦点を当てています。


1
うーん... javapuzzlers.comjimbrooks.org /web/python / #Pitfalls。私が言うと思い加速C ++(1例)ずっと焦点を当て、よりこれらが何よりも、どのように書き込みコードの上...
ジェリー棺

1
それぞれの言語のエッジケースを指摘するリソースの例をいくつか紹介しました。奇妙に見えるとあなたはかなり確実(Pythonのリストのようなものが近くにありますが)、彼らが働くだろうかじゃない事が... C ++は全体の持っている業界の事を指摘見える方法で動作はあなたが期待していないことを完全に有効に。
赤い汚れ

3

テンプレートが多すぎると、最初はバグにならない場合があります。しかし、時間が経つにつれて、人々はそのコードを変更する必要があり、巨大なテンプレートを理解するのに苦労します。そのとき、バグが入り込みます-誤解が「コンパイルして実行する」コメントを引き起こし、ほとんど正しいコードになりがちです。

一般的に、3レベルのディープジェネリックテンプレートを実行しているのを見た場合は、停止して、それを1つに減らす方法を考えます。多くの場合、問題は関数またはクラスを抽出することで解決されます。


8
要件の変更に直面して複雑なコードを維持すると、多くの労力をかけずに常にバグ発生します、テンプレートについて特に特別なことはありません。
フレッドナーク

2

警告:これは、「ユーザーの知らない人」が彼の答えでリンクした話の批評ほどではありません。

彼の最初の主要なポイントは(おそらく)「常に変化する標準」です。実際には、彼が提供するすべての例は、標準が存在する前の C ++の変更に関連しています。1998年(最初のC ++標準が完成したとき)以来、言語への変更はごくわずかでした。実際、多くの人が本当の問題はもっと多くの変更を加えるべきだと主張しています。私は、元のC ++標準に準拠したすべてのコードが現在の標準に準拠していることを合理的に確信しています。多少確かではありませんが、何かが急速に(そしてまったく予期せずに)変更されない限り、これは今後のC ++標準(理論的には、使用されるすべてのコードexport壊れますが、実質的には存在しません。実用的な観点からは問題ではありません)。そのような主張をすることができる他の言語、OS(またはコンピューター関連の他の多くの言語)はほとんど考えられません。

その後、彼は「常に変化するスタイル」に入ります。繰り返しますが、彼のポイントのほとんどはナンセンスにかなり近いです。彼はfor (int i=0; i<n;i++)「古くて壊れた」とfor (int i(0); i!=n;++i)「新しい辛さ」として特徴付けようとします。現実には、そのような変更が意味をなすタイプがありますがint、違いはありません-何かを得ることができたとしても、良いコードや正しいコードを書くために必要なことはめったにありません。せいぜい、彼はモグラ塚から山を作っています。

彼の次の主張は、C ++が「間違った方向に最適化する」ことです。具体的には、優れたライブラリの使用は簡単であると認めながら、C ++は「優れたライブラリの作成をほとんど不可能にします」。ここで、私は彼の最も根本的な間違いの一つだと信じています。実際には、ほとんどすべての言語に適したライブラリを作成することは非常に困難です。最低限、優れたライブラリを作成するには、問題のドメインを十分に理解して、そのドメイン内の(または関連する)可能性のある多数のアプリケーションでコードが機能することが必要です。C ++が実際に行うことのほとんどは「水準を引き上げる」ことです。ライブラリどれほど優れているかを見た後、人々は、そうでない場合のようなドレックの書き方に戻ることはほとんどありません。本当に優れたコーダーはかなりの数のライブラリを作成し、それを「残りの人」が(簡単に、彼が認めているように)使用できるようにします。これは本当に「それはバグではなく、機能です」というケースです。

私はすべてのポイントを順番にヒットしようとはしませんが(ページを取得します)、彼の終了ポイントに直接スキップします。Bjarneは「プログラム全体の最適化を使用して、未使用の仮想関数テーブルとRTTIデータを排除できる。このような分析は、動的リンクを使用しない比較的小規模なプログラムに特に適している」と述べています。

彼はこれを、「これは本当に難しい問題」という支持されていない主張をすることで批判し、それを停止する問題と比較することさえします。現実には、それは何の種類でもありません-実際、Zortech C ++(1980年代に遡るMS-DOS用のほとんど最初の C ++コンパイラ)に含まれていたリンカーがこれを行いました。おそらく外部データのすべてのビットが削除されたことを確認することは困難ですが、それでもかなり公平な仕事をすることは完全に合理的です。

ただし、それにもかかわらず、はるかに重要な点は、いずれにしても、ほとんどのプログラマーにとってこれはまったく無関係であることです。かなりの量のコードを逆アセンブルした私たちが知っているように、ライブラリをまったく持たないアセンブリ言語を書かない限り、実行可能ファイルにはほぼ確実にかなりの量の「もの」(典型的な場合はコードとデータの両方)が含まれますおそらく実際に使用していることは言うまでもなく、おそらく知らないでしょう。ほとんどの人にとって、ほとんどの場合、それは重要ではありません。最も小さな組み込みシステム向けに開発しているのでない限り、余分なストレージ消費は単純に無関係です。

最後に、この暴言はLinusの愚かさよりも少し多くの内容を持っているのは事実ですが、それは当然のことながら、それにふさわしいかすかな賞賛を与えています。


1

やむを得ない状況のためにC ++でコーディングしなければならなかったCプログラマーとして、ここに私の経験があります。私が使用しているものはC ++で、ほとんどCに固執しているものはほとんどありません。主な理由は、C ++をあまりよく理解していないからです。C ++の複雑さと、C ++での良いコードの書き方を教えてくれるメンターがいました/いませんでした。また、非常に優れたC ++コードからのガイダンスなしでは、C ++で優れたコードを記述することは非常に困難です。私見、これはC ++の最大の欠点です。初心者に手を差し伸べてくれる優れたC ++プログラマーを見つけるのは難しいからです。

私が通常見たパフォーマンスのヒットのいくつかは、STLの魔法のようなメモリ割り当てによるものです(はい、アロケータを変更できますが、C ++で始めたときに誰がそれをしますか?)。通常、ベクトルは配列を内部で使用し、抽象化は非常に効率的であるため、ベクトルと配列は同様のパフォーマンスを提供するという議論をC ++の専門家が耳にします。ベクトルアクセスと既存の値の変更については、これが実際に当てはまることがわかりました。ただし、新しいエントリの追加、ベクターの構築および破棄には当てはまりません。gprofは、アプリケーションの累積時間の25%がベクターコンストラクター、デストラクタ、memmove(新しい要素を追加するためのベクター全体の再配置)およびその他のオーバーロードされたベクター演算子(++など)に費やされることを示しました。

同じアプリケーションでは、somethingSmallのベクターを使用してsomethingBigを表しました。somethingBig内のsomethingSmallのランダムアクセスの必要はありませんでした。それでも、リストの代わりにベクトルが使用されました。ベクトルが使用された理由は?元のコーダーはベクトルの構文のような配列に精通しており、リストに必要なイテレータにはあまり精通していなかったためです(そう、彼はCのバックグラウンドから来ました)。C ++を正しく機能させるには、専門家からの多くのガイダンスが必要であることを証明し続けます。Cには、抽象化がまったくない基本的な構成要素がほとんどないため、C ++よりはるかに簡単に正しく構成できます。



0

STLとboostは、ソースコードレベルで移植可能です。Linusが言っていることは、C ++にはABI(アプリケーションバイナリインターフェイス)がないことだと思います。したがって、リンクするすべてのライブラリを、同じコンパイラバージョンと同じスイッチでコンパイルするか、dll境界のC ABIに制限する必要があります。私もその悩みの種を見つけました。しかし、サードパーティのライブラリを作成しているのでなければ、ビルド環境を制御できるはずです。私はC ABIに自分自身を制限することは面倒の価値がないと思う あるDLLから別のDLLに文字列、ベクトル、およびスマートポインターを渡すことができるという利便性は、コンパイラのアップグレードまたはコンパイラスイッチの変更時にすべてのライブラリを再構築する手間がかかります。私が従う黄金律は次のとおりです。

-実装ではなく、インターフェイスの再利用を継承

-継承よりも集約を優先する

-メンバーメソッドよりも可能な限り自由な関数を優先する

-常にRAIIイディオムを使用して、コードを非常に例外安全にします。キャッチしようとしないでください。

-スマートポインターを使用し、裸(非所有)ポインターを避けます

-参照セマンティクスよりも値セマンティクスを優先する

-車輪を再発明しないで、stlとboostを使用してください

-Pimplイディオムを使用してプライベートを隠したり、コンパイラファイアウォールを提供したりします。


-6

;少なくともVCの一部のバージョンでは、クラス宣言の最後にファイナルを置かない。


4
これはおそらく初心者にとって非常によくある間違いです(基本的な構文をまだ学んでいる人にとってはほとんど何でも)が、自分自身を有能と呼び、この間違いを注目に値する多くの人がいますか?
フレッドナーク

1
コンパイラがセミコロンの欠如とは関係のないエラーをあなたに与えたという理由だけでそれを書きました。
マルコムスタピック

2
ええ、まったく同じエラーは、Cコンパイラから得られるものです。
ミルチアチレア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.