C#は、C ++よりも「自分にぶら下がるロープ」を提供しますか?[閉まっている]


14

Joel Spolskyは、C ++を「自分を吊るすのに十分なロープ」と見なしました。実際、彼はScott Meyersによる「Effective C ++」を要約していました。

それは基本的に、C ++は自分を吊るすのに十分なロープであり、さらに数マイルのロープ、そしてM&Mを装った自殺薬がいくつかあるという本です...

私は本のコピーを持っていませんが、本の多くはランタイムがあなたのためにそれらの問題を管理するので、C#で意味がないと思われるメモリ管理の落とし穴に関連する兆候あります。

私の質問は次のとおりです。

  1. C#は、注意深いプログラミングによってのみC ++で回避される落とし穴を回避しますか?その場合、どの程度、どのように回避されますか?
  2. C#には、新しいC#プログラマーが知っておくべき、新しい異なる落とし穴がありますか?もしそうなら、なぜC#の設計によってそれらを回避できなかったのでしょうか?

10
FAQから:Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.。これはそのような質問として適格だと思います
...-Oded

@Oded文字制限の見出しの質問を参照していますか?または、投稿の本文に3つ以上のより正確な質問がありますか?
-alx9r

3
率直に言って-タイトルとの両方の「より正確な質問」の。
-Oded

3
この質問についてメタディスカッションを開始しました。
Oded

1
削除された3番目の質問については、Bill WagnerのEffective C#シリーズ(現在3冊)で、このテーマで読んだ他の何よりもC#のプログラミングについてよく学びました。EC#のMartinsのレビューは、Effective C ++を直接置き換えることはできないという点で正しいですが、そうすべきだと考えるのは間違っています。簡単なミスを心配する必要がなくなったら、さらに難しいミスに移る必要があります。
マークブース

回答:


33

C ++とC#の根本的な違いは、未定義の動作に起因します

手動のメモリ管理とは関係ありませんどちらの場合も、それは解決された問題です。

C / C ++:

C ++では、間違えた場合の結果は未定義です。
または、システムについて特定の種類の仮定(符号付き整数オーバーフローなど)をしようとすると、プログラムが未定義になる可能性があります。

たぶん、この3部シリーズ読んで未定義の動作上を。

これにより、C ++が非常に高速になります。コンパイラは、問題が発生したときに何が起こるかを心配する必要がないため、正確性のチェックを回避できます。

C#、Javaなど

C#では、あなたがしている保証は多くのミスが、例外として、あなたの顔に爆破されること、そしてあなたが保証している多くの基盤となるシステムについて。
つまり基本的に高速C ++などとしてのC#を作るための障壁が、それはまた、C ++の安全を作るための基本的な障壁だし、それは、C#が簡単で作業してデバッグすることができます。

それ以外はすべてグレービーです。


未定義のものはすべて実装によって実際に定義されているため、Visual Studioで符号なし整数をオーバーフローさせた場合、適切なコンパイラフラグをオンにすると例外が発生します。今、私はこれがあなたが話していることであることを知っていますが、それは未定義の動作ではなく、人々が通常それをチェックしないということです。(operator ++のような真に未定義の動作と同じで、各コンパイラーによって適切に定義されます)。C#でも同じことが言えますが、実装は1つだけです。Monoで実行した場合の「未定義の動作」はたくさんあります。bugzilla.xamarin.com/show_bug.cgi?id=310
gbjbaanb

1
それは本当に定義されているのですか、それとも現在のバージョンのWindows上の現在の.net実装が行うものによってのみ定義されるのですか c ++の未定義の動作でさえ、g ++が実行するものとして定義すると完全に定義されます。
マーティンベケット

6
符号なし整数のオーバーフローはまったくUBではありません。UBである符号付き整数がオーバーフローしています。
-DeadMG

6
@gbjbaanb:DeadMGが言ったように-符号付き整数オーバーフロー未定義です。それはだない実装定義します。これらのフレーズは、C ++標準で特定の意味を持ち、同じものではありません。その間違いをしないでください。
user541686

1
@CharlesSalvia:ええと、C#よりも「C ++がCPUキャッシュを簡単に活用できるようにする方法」を正確に教えてください。また、C#では、C#ではできないメモリをどのように制御できますか?
user541686

12

C#は、注意深いプログラミングによってのみC ++で回避される落とし穴を回避しますか?その場合、どの程度、どのように回避されますか?

ほとんどの場合、そうでないものもあります。そしてもちろん、それはいくつか新しいものを作ります。

  1. 未定義の動作 -C ++の最大の落とし穴は、未定義の言語が非常に多いことです。これらのことを行うと、コンパイラーは文字通り宇宙を爆破することができ、大丈夫です。当然、これは一般的でありませんが、プログラムが1台のマシンで正常に動作し、実際には別のマシンでは動作しない正当な理由があることかなり一般的です。さらに悪いことに、微妙に異なる行動をします。C#の仕様には未定義の動作がいくつかありますが、まれであり、頻繁に使用されない言語の領域でも同様です。C ++には、ステートメントを作成するたびに未定義の動作が発生する可能性があります。

  2. メモリリーク -これは、最新のC ++にとってはそれほど問題ではありませんが、初心者にとっては、C ++によってその寿命の約半分でメモリリークが非常に簡単になりました。効果的なC ++は、この懸念を解消するための実践の進化の真っaround中にありました。ただし、C#メモリをリークする可能性があります。人々が遭遇する最も一般的なケースは、イベントキャプチャです。オブジェクトがあり、そのメソッドの1つをイベントのハンドラーとして配置する場合、そのイベントの所有者はオブジェクトが死ぬためにGCされる必要があります。ほとんどの初心者は、イベントハンドラーが参照としてカウントされることを認識していません。また、メモリリークを引き起こす可能性のある使い捨てリソースを破棄しないという問題もありますが、これらは以前のC ++のポインタほど一般的ではありません。

  3. コンパイル -C ++には遅延コンパイルモデルがあります。これは、それをうまく利用し、コンパイル時間を抑えるためのいくつかのトリックにつながります。

  4. 文字列 -現代のC ++はこれを少し改善しますが、char*2000年以前のすべてのセキュリティ侵害の〜95%に責任がありstd::stringます。 。そして、それはあなたがユニコードのサポートを必要としないことを祈っています。

そして実際、それは氷山の一角です。主な問題は、C ++が初心者にとって非常に貧弱な言語であるということです。それはかなり一貫性がなく、古い、本当に本当に悪い落とし穴の多くは、イディオムを変えることで対処されてきました。問題は、初心者がEffective C ++のようなものからイディオムを学ぶ必要があることです。C#はこれらの問題の多くを完全に排除し、学習パスに沿って進むまで残りの問題を軽減します。

C#には、新しいC#プログラマーが知っておくべき、新しい異なる落とし穴がありますか?もしそうなら、なぜC#の設計によってそれらを回避できなかったのでしょうか?

イベント「メモリリーク」の問題について言及しました。これは、言語ができないことをプログラマが期待しているほど、言語の問題ではありません。

もう1つは、C#オブジェクトのファイナライザーがランタイムによって実行されることが技術的に保証されていないことです。これは通常は重要ではありませんが、いくつかの事柄が予想とは異なるように設計されます。

プログラマーが遭遇するもう1つの半落とし穴は、匿名関数のキャプチャセマンティクスです。変数をキャプチャすると、変数がキャプチャされます。例:

List<Action> actions = new List<Action>();
for(int x = 0; x < 10; ++x ){
    actions.Add(() => Console.WriteLine(x));
}

foreach(var action in actions){
    action();
}

素朴に考えられていることをしません。これは1010回印刷します。

私が忘れている他の多くの人がいると確信していますが、主な問題はそれらがあまり普及していないことです。


4
メモリリークは過去のものであり、そうですchar*。言うまでもなく、C#でメモリを問題なくリークできることは言うまでもありません。
DeadMG

2
テンプレートを「装飾文字列の貼り付け」と呼ぶのは少しばかりです。テンプレートは、C ++の最高の機能の1つです。
チャールズサルビア

2
@CharlesSalvia確かに、彼らはC ++の本当に際立った特徴。そして、はい、それはおそらくコンパイルの影響を単純化しすぎているでしょう。ただし、特に注意しないと、コンパイル時間と出力サイズに不均衡に影響します。
テラスティン

2
確かに、@ deadMGは、C ++で使用/必要とされるテンプレートメタプログラミングトリックの多くが...別のメカニズムを介してより適切に実装されると主張します。
テラスティン

2
type_traitsの全体のポイントは、時の型情報を取得することです@Telastyn コンパイル時は、使用して、特定の方法に特化テンプレートや過負荷機能のようなものを行うために、この情報を使用できるようにenable_if
チャールズサルビア

10

私の意見では、C ++の危険性はいくぶん誇張されています。

本質的な危険はこれです。C#ではunsafeキーワードを使用して「安全でない」ポインター操作を実行できますが、C ++(ほとんどがCのスーパーセットである)を使用すると、いつでもポインターを使用できます。メモリーリーク、バッファーオーバーフロー、ぶら下がりポインターなど、ポインターの使用に固有の通常の危険性(Cと同じ)に加えて、C ++は、物事を真剣に台無しにする新しい方法を導入します。

Joel Spolskyが言っていたこの「余分なロープ」は、基本的に1つのことです。「Rule of 3」としても知られる独自の記憶を内部で管理するクラスを書くことですC ++ 11のof of 4またはRule of 5)。つまり、内部で独自のメモリ割り当てを管理するクラスを作成したい場合は、何をしているのかを知る必要があります。そうしないと、プログラムがクラッシュする可能性があります。コンストラクター、コピーコンストラクター、デストラクター、および代入演算子を慎重に作成する必要がありますが、これは驚くほど簡単に間違えやすく、多くの場合、実行時に奇妙なクラッシュを引き起こします。

しかし、実際の毎日のC ++プログラミングでは、独自のメモリを管理するクラスを作成することは非常にまれです。したがって、C ++プログラマはこれらの落とし穴を回避するために常に「注意」する必要があると誤解されます。通常、次のようなことを行うだけです。

class Foo
{
    public:

    Foo(const std::string& s) 
        : m_first_name(s)
    { }

    private:

    std::string m_first_name;
};

このクラスは、JavaまたはC#で行うことと非常によく似ています-明示的なメモリ管理を必要とせず(ライブラリクラスstd::stringがすべてを自動的に処理するため)、「Rule of 3」はデフォルトからまったく必要ありませんコピーコンストラクタと代入演算子は問題ありません。

次のようなことをしようとするときだけです:

class Foo
{
    public:

    Foo(const char* s)
    { 
        std::size_t len = std::strlen(s);
        m_name = new char[len + 1];
        std::strcpy(m_name, s);
    }

    Foo(const Foo& f); // must implement proper copy constructor

    Foo& operator = (const Foo& f); // must implement proper assignment operator

    ~Foo(); // must free resource in destructor

    private:

    char* m_name;
};

この場合、初心者が割り当て、デストラクタ、およびコピーコンストラクタを正しく取得するのは難しい場合があります。しかし、ほとんどの場合、これを行う理由はありません。C ++では、std::stringやなどのライブラリクラスを使用することで、99%の時間で手動メモリ管理を簡単に回避できますstd::vector

別の関連する問題は、例外がスローされる可能性を考慮しない方法でメモリを手動で管理することです。お気に入り:

char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;

some_function_which_may_throw()実際に例外スローされた場合、割り当てられたメモリsは再利用されないため、メモリリークが発生します。しかし、繰り返しますが、実際には、これは「Rule of 3」が実際にはもうあまり問題ではないのと同じ理由でほとんど問題ではありません。生のポインタを使用して実際に独自のメモリを管理することは非常にまれです(通常は不要です)。上記の問題を回避するには、std::stringまたはを使用するだけでstd::vector、例外がスローされた後のスタックの巻き戻し中にデストラクタが自動的に呼び出されます。

そのため、ここでの一般的なテーマは、自動初期化/破棄、コピーコンストラクター、例外など、Cから継承されなかった C ++機能の多くが、C ++で手動メモリ管理を行う際にプログラマーに特に注意を払うことです。ただし、これは、最初に手動のメモリ管理を行う場合にのみ問題になります。これは、標準のコンテナとスマートポインタを使用している場合にはもうほとんど必要ありません。

だから、私の意見では、C ++は余分なロープをたくさん与えてくれますが、それを使ってぶらぶらする必要はほとんどありません。ジョエルが話していた落とし穴は、現代のC ++で簡単に避けることができます。


これはC ++ 03では3つのルールでしたが、現在はC ++ 11では4つのルールです。
DeadMG

1
コンストラクターのコピー、コンストラクターの移動、割り当てのコピー、割り当ての移動、およびデストラクターについては、「5の規則」と呼ぶことができます。しかし、適切なリソース管理のためだけに、移動セマンティクスが常に必要なわけではありません。
チャールズサルビア

移動とコピーを個別に割り当てる必要はありません。コピーアンドスワップイディオムでは、両方の演算子を1つで実行できます。
-DeadMG

2
質問に答えますDoes C# avoid pitfalls that are avoided in C++ only by careful programming?。答えは「そうではありません。なぜなら、ジョエルが現代のC ++で話していた落とし穴を避けるのは簡単だからです」
チャールズサルビア

1
IMO、C#やJavaなどの高レベル言語は、メモリ管理やその他の役立つものを提供しますが、必ずしも想定どおりに機能するとは限りません。あなたはまだコード設計の面倒を見ることになりますので、メモリリークを残しません(これはC ++で正確に呼ぶものではありません)。私の経験から、デストラクタが呼び出され、ほとんどの場合はクリーンアップを行うことを知っているので、C ++でメモリを管理するのは簡単です。結局のところ、C ++には、設計が効率的なメモリ管理を許可しない場合のためのスマートポインターがあります。C ++は素晴らしいですが、ダミーには向いていません。
-Pijusn

3

私は本当に同意しません。たぶん1985年に存在したC ++よりも落とし穴は少ないでしょう。

C#は、注意深いプログラミングによってのみC ++で回避される落とし穴を回避しますか?その場合、どの程度、どのように回避されますか?

あんまり。Rule of Threeのようなルールは、C ++ 11のおかげでunique_ptrshared_ptr標準化されて。漠然と賢明な方法で標準クラスを使用することは「注意深いコーディング」ではなく、「基本的なコーディング」です。さらに、手動のメモリ管理のようなことをするのにまだ十分に愚かで、知識がない、またはその両方であるC ++人口の割合は、以前よりはるかに低くなっています。現実には、そのようなルールを実証したい講師は、適用可能な例を見つけるために数週間を費やさなければなりません。スタンダードクラスは、考えられるほとんどすべてのユースケースをカバーしているからです。多くの効果的なC ++テクニックは、ドードーの方法と同じ方法で進んでいます。他の多くは、実際にはそれほどC ++固有ではありません。そうねぇ。最初の項目をスキップすると、次の10は次のとおりです。

  1. CのようにC ++をコーディングしないでください。これは実際には単なる常識です。
  2. インターフェイスを制限し、カプセル化を使用します。おっと。
  3. 2フェーズの初期化コードライターを危険にさらす必要があります。おっと。
  4. 値セマンティクスが何であるかを知ってください。これは本当にC ++固有ですか?
  5. インターフェースを再び制限します。今回は少し異なる方法で。おっと。
  6. 仮想デストラクタ。うん。これはおそらくまだある程度有効です。finalそして、overrideこの特定のゲームをより良く変えるのを助けました。デストラクタを作成してください。デストラクタoverrideを作成していない人から継承した場合、すばらしいコンパイラエラーが保証されますvirtual。クラスを作るfinalと、仮想デストラクタがなくても、貧弱なスクラブが偶然に現れを継承することはありません。
  7. クリーンアップ関数が失敗すると、悪いことが起こります。これは実際にはC ++に固有のものではありません。JavaとC#の両方について同じアドバイスを見ることができます。失敗する可能性のあるクリーンアップ関数を持つことは、単純に悪いことであり、この項目についてはC ++もOOPもありません。
  8. コンストラクターの順序が仮想関数に与える影響に注意してください。陽気なことに、Java(現在または過去のいずれか)では、単にDerivedクラスの関数を誤って呼び出します。これは、C ++の動作よりもさらに悪いことです。とにかく、この問題はC ++に固有のものではありません。
  9. オペレーターのオーバーロードは、人々が期待するとおりに動作するはずです。それほど具体的ではありません。地獄、特定の演算子をオーバーロードすることすらほとんどありません。同じことはどの関数にも適用できます。1つの名前を付けてから、完全に直感的ではないようにします。
  10. これは実際には悪い習慣と見なされています。非常に例外的に安全な割り当て演算子はすべて、自己割り当てをうまく処理します。また、自己割り当ては事実上論理的なプログラムエラーであり、自己割り当てのチェックはパフォーマンスコストの価値がありません。

明らかに、すべての単一の有効なC ++項目を説明するわけではありませんが、それらのほとんどは単純に基本的な概念をC ++に適用しているだけです。値型のオブジェクト指向のオーバーロード可能な演算子言語にも同じアドバイスがあります。仮想デストラクタは、C ++の落とし穴であり、まだfinal有効な唯一のものです。ただし、C ++ 11のクラスではほぼ間違いなく、以前ほど有効ではありません。Effective C ++は、OOPとC ++の特定の機能を適用するというアイデアがまだ非常に新しいときに書かれたことを思い出してください。これらの項目は、C ++の落とし穴に関するものではなく、Cからの変更に対処する方法と、OOPを正しく使用する方法に関するものです。

編集:C ++の落とし穴には、の落とし穴のようなものは含まれませんmalloc。つまり、Cコードで見つけることができるすべての落とし穴は、安全でないC#コードでも同様に見つけることができるので、特に関連していませんコード。標準も定義しgotoていますが、それを使用してスパゲッティの混乱の巨大な山を書く場合、言語の問題ではなく、あなたの問題だと思います。「注意深いコーディング」と「言語の基本的なイディオムに従う」には大きな違いがあります。

C#には、新しいC#プログラマーが知っておくべき、新しい異なる落とし穴がありますか?もしそうなら、なぜC#の設計によってそれらを回避できなかったのでしょうか?

using吸います。本当にそうです。そして、なぜもっと良いことが行われなかったのか、私にはわかりません。また、Base[] = Derived[]元のデザイナーがテンプレートがC ++で大成功したことに気付かず、「すべてを継承し、すべてのタイプセーフを失おう」と判断したため、Objectのほとんどすべての使用が賢明な選択でした。 。また、参加者との競合状態やその他の楽しみなど、意外な驚きを見つけることができると信じています。次に、テンプレートと比較してジェネリックが恐ろしく吸う方法、aにすべてを本当に不要に強制配置するclassなど、他の一般的なものがあります。


5
しかし、教育を受けたユーザーベースまたは新しい構成体は、実際にロープを減らしていません。それらは単なる回避策であるため、ハングアップする人は少なくなります。これはすべて、Effective C ++と言語の進化におけるそのコンテキストに関する優れた解説です。
テラスティン

2
いいえ。EffectiveC ++の多くの項目が、どのような値型のオブジェクト指向言語にも同様に適用できる概念であるということです。そして、Cではなく実際のC ++をコーディングするようにユーザーベースを教育することは、C ++が提供するロープを確実に減らすことです。また、新しい言語構造ロープ減らしていることを期待します。それは、C ++ Standardが定義mallocしているからといって、それを行うべきだという意味ではないということですgoto
DeadMG

2
C ++のC部分を使用することはunsafe、C#ですべてのコードを書くことと同じです。必要に応じて、CのようなC#コーディングの落とし穴もすべてリストできます。
DeadMG

@DeadMG:だから本当に質問は、「C ++プログラマーはCプログラマーである限り自分を掛けるのに十分なロープを持っている」べきです
gbjbaanb

「さらに、手動のメモリ管理のようなことをするのにまだ十分に愚かで、知らされていない、またはその両方であるC ++人口の割合は、以前よりはるかに低くなっています。」引用が必要です。
dan04

3

C#は、注意深いプログラミングによってのみC ++で回避される落とし穴を回避しますか?その場合、どの程度、どのように回避されますか?

C#には次の利点があります。

  • Cとの後方互換性がないため、構文的には便利であるが現在は不適切なスタイルと見なされている「悪」言語機能(生のポインタなど)の長いリストを避ける。
  • 値セマンティクスの代わりに参照セマンティクスを使用すると、少なくとも10個の有効なC ++アイテムが無効になります(ただし、新しい落とし穴が生じます)。
  • 実装定義の動作がC ++よりも少ない。
    • 具体的には、C ++の文字エンコーディングにcharstring等実装定義です。WindowsのUnicodeアプローチ(wchar_tUTF-16、char廃止された「コードページ」)と* nixアプローチ(UTF-8)の分裂は、クロスプラットフォームコードで大きな困難を引き起こします。C#、OTOHは、a stringがUTF-16 であることを保証します。

C#には、新しいC#プログラマーが知っておくべき、新しい異なる落とし穴がありますか?

はい: IDisposable

C#の「Effective C ++」に相当する本はありますか?

Effective C#と呼ばれる本があり、その構造はEffective C ++に似ています


0

いいえ、C#(およびJava)はC ++より安全ではありません

C ++はローカルで検証可能です。C ++で1つのクラスを検査し、参照されているすべてのクラスが正しいと仮定して、クラスがメモリやその他のリソースをリークしないことを確認できます。JavaまたはC#では、参照されるすべてのクラスをチェックして、何らかのファイナライズが必要かどうかを判断する必要があります。

C ++:

{
   some_resource r(...);  // resource initialized
   ...
}  // resource destructor called, no leaks here

C#:

{
   SomeResource r = new SomeResource(...); // resource initialized
   ...
} // did I need to finalize that?  May I should have used 'using' 
  // (or in Java, a grotesque try/finally construct)?  No way to tell
  // without checking the documentation for SomeResource

C ++:

{
    auto_ptr<SomeInterface> i = SomeFactory.create(...);
    i->f(...);
} // automatic finalization and memory release.  A new implementation of
  // SomeInterface can allocate and free resources with no impact
  // on existing code

C#:

{
   SomeInterface i = SomeFactory.create(...);
   i.f(...);
   ...
} // Sure hope someone didn't create an implementation of SomeInterface
  // that requires finalization.  In C# and Java it is necessary to decide whether
  // any implementation could require finalization when the interface is defined.
  // If the initial decision is 'no finalization', then no future implementation  
  // can acquire any resource without creating potential leaks in existing code.

3
...現代のIDEでは、IDisposableから何かが継承されるかどうかを判断するのは非常に簡単です。主な問題は、使用するために知っておく必要があることですauto_ptr(またはその親族のいくつか)。それがことわざです。
テラスティン

2
@Telastynいいえ、ポイントは、スマートポインターを必要としないことが本当にわかっている場合を除き、常にスマートポインターを使用することです。C#では、usingステートメントは、参照しているロープのようなものです。(つまり、C ++では、スマートポインターを使用することを覚えておく必要があります。常にusingステートメントを使用することを覚えていなければならないのに、なぜC#はそれほど悪くないのですか)
gbjbaanb

1
@gbjbaanbなぜなら何のため?ほとんどのC#クラスは5%が使い捨てですか?そして、それらが使い捨てであればそれらを処分する必要があることを知っています。C ++では、すべてのオブジェクトは使い捨てです。また、特定のインスタンスを処理する必要があるどうかもわかりません。ファクトリーからではないポインターが返されるとどうなりますか?それらをきれいにするのはあなたの責任ですか?あるべきではないが、時々そうである。繰り返しますが、常にスマートポインターを使用する必要があるからといって、オプションが存在しなくなるわけではありません。特に初心者にとって、これは重大な落とし穴です。
テラスティン

2
@Telastyn:使用することを知ることauto_ptrは、使用IEnumerableすることを知ること、またはインターフェースを使用することを知ることと同じくらい簡単です。あるいは、通貨などに浮動小数点を使用しないでください。DRYの基本的なアプリケーションです。プログラム方法の基本を知っている人は誰もその間違いを犯さないでしょう。とは異なりusing。問題usingは、それが使い捨てであるかどうかにかかわらず、すべてのクラスについて知る必要があることです(そして、決して変わらないことを願っています)。
-DeadMG

2
kevin:ええ、あなたの答えは意味がありません。間違っているのはC#のせいではありません。あなたはない、NOT適切に書かれたC#コードでファイナライザに依存しますDisposeメソッドを持つフィールドがある場合は、実装する必要がありますIDisposable(「適切な」方法)。クラスがそれを実行し(C ++でクラスにRAIIを実装するのと同等)、使用する場合using(C ++のスマートポインターのようなもの)、すべてが完全に機能します。ファイナライザは、主に事故を防ぐことを目的Disposeとしています- 正確性に責任があり、それを使用していない場合、それはあなたのせいであり、C#のせいではありません。
user541686

0

はい、メモリを解放してC#で使用することは不可能だと思います(マネージドモードで、安全でないモードに入らないと仮定)。

しかし、信じられないほど多くの人が知らないC ++でのプログラミング方法を知っているなら。大丈夫です。チャールズサルビアのように、クラスはすべて既存のSTLクラスで処理されるため、記憶を実際に管理しません。私はめったにポインターを使用しません。実際、私は単一のポインターを使用せずにプロジェクトに行きました。(C ++ 11はこれを簡単にします)。

タイプミスやばかげたミスなど(例:if (i=0)bc ==をすばやく押すとキーがスタックする)については、コンパイラーが文句を言います。他の例はbreak、switchステートメントでの忘れ、関数での静的変数の宣言を許可しないことです(これは時々嫌いですが、良いアイデアです)。


4
JavaとC#は、参照の平等に使用し、値の平等を導入することにより、=/ ==問題をさらに悪化させました。貧しいプログラマーは、変数が 'double'か 'Double'かを追跡し、正しいバリアントを呼び出すようにしてください。==.equals
ケビンクライン

@kevincline 1が、C#でstructあなたがすることができる==時間の1の大半は文字列のみ、int型と浮動小数点数(すなわち唯一の構造体のメンバーを)持っていますので、非常にうまく機能しています。私のコードでは、配列を比較したい場合を除いて、この問題は決して発生しません。リストまたは非構造型(string、int、float、DateTime、KeyValuePairなど)を比較することはないと思います

2
Pythonは==、値の等価性とis参照の等価性に使用することで、それを正しく実現しました。
dan04

@ dan04-C#にはいくつの平等性があると思いますか?優れたACCUのライトニングトークを参照してください:一部のオブジェクトが他よりも等しい
マーク・ブース
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.