39

C++標準が未定義の動作として属性を付ける状況がいくつかあります。たとえば、を割り当ててから、未定義の動作である(ではなく)new[]を解放しようとすると、何かが発生する可能性があります。動作する可能性があり、ひどくクラッシュする可能性があり、サイレントに何かが破損し、時限問題が発生する可能性があります。deletedelete[]

これを説明するのはとても問題があります。彼らは「これが機能する」ことを「証明」し始め(実際に使用するC ++実装で機能するため)、「これで何が間違っている可能性があるか」と尋ねます。そのようなコードを書かないように動機付けるために、どのような簡潔な説明をすることができますか?

4

19 に答える 19

51

未定義とは、明示的に信頼できないことを意味します。ソフトウェアは信頼できるものでなければなりません。他に多くのことを言う必要はありません。

凍った池は、未定義の歩行面の良い例です。一度通過したからといって、特に4シーズンを計画している場合は、紙のルートにショートカットを追加する必要があるわけではありません。

于 2010-02-10T09:09:40.747 に答える
33

2つの可能性が思い浮かびます。

  1. 「深夜に高速道路を反対方向に運転して生き残ることができるからといって、定期的にやってみませんか?」と尋ねることができます。

  2. より複雑な解決策は、異なるコンパイラー/実行環境をセットアップして、異なる状況下でどのように見事に失敗するかを示すことかもしれません。

于 2010-02-10T08:57:19.567 に答える
23

「おめでとうございます。コンパイラがその操作に対して行う動作を定義しました。世界に存在する他の200のコンパイラが示す動作に関するレポートが、明日の午前10時までに私の机に置かれることを期待しています。失望しないでください。私は今、あなたの将来は有望に見えます!」

于 2010-02-10T08:57:33.673 に答える
13

標準から引用するだけです。彼らがそれを受け入れることができない場合、彼らはC++プログラマーではありません。クリスチャンは聖書を否定しますか?;-)

1.9プログラムの実行

  1. この国際規格のセマンティック記述は、パラメーター化された非決定論的抽象マシンを定義します。[...]

  2. 抽象マシンの特定の側面と操作は、この国際規格で実装定義として説明されています(たとえばsizeof(int))。これらは、抽象マシンのパラメーターを構成します。各実装には、これらの点での特性と動作を説明するドキュメントを含める必要があります。[...]

  3. 抽象マシンのその他の特定の側面と操作は、この国際規格では指定されていないものとして説明されています(たとえば、関数の引数の評価の順序)。可能な場合、この国際規格は一連の許容可能な動作を定義します。これらは、抽象マシンの非決定論的側面を定義します。[...]

  4. この国際規格では、他の特定の操作が未定義として説明されています(たとえば、nullポインターの逆参照の影響)。[注:この国際規格は、未定義の動作を含むプログラムの動作に要件を課していません。—エンドノート]

それ以上に明確にすることはできません。

于 2010-02-10T11:03:10.377 に答える
11

彼らがコードを正しく書かなかった場合、彼らの次の業績評価は幸せなものではないだろうと私は説明します。それはほとんどの人にとって十分な「動機」です。

于 2010-02-10T10:01:38.620 に答える
3

ジョン・ウッズ

つまり、要素が定義されていない構造体でsizeof()を使用することはできません。使用すると、悪魔が鼻から飛び出す可能性があります。

「悪魔はあなたの鼻から飛び出すかもしれない」は単にすべてのプログラマーの語彙の一部でなければなりません。

もっと要点を言えば、移植性について話してください。さまざまなコンパイラはもちろん、プログラムをさまざまなOSに頻繁に移植する必要があることを説明します。現実の世界では、移植は通常、元のプログラマー以外の人によって行われます。これらのポートの一部は組み込みデバイスにも対応しており、コンパイラが想定とは異なる方法で決定したことを発見するのに莫大なコストがかかる可能性があります。

于 2010-02-10T10:23:11.873 に答える
3

テスト中にコードがクラッシュするまで、彼らに試してもらいましょう。そうすれば言葉は必要なくなります。

問題は、初心者(私たち全員がそこにいた)にはある程度のエゴと自信があるということです。それは大丈夫。実際、そうしなければ、プログラマーになることはできません。彼らを教育することは重要ですが、彼らをサポートすることはそれほど重要ではなく、彼ら自身への信頼を損なうことによって彼らの旅のスタートを切らないでください。礼儀正しく、言葉ではなく事実で自分の立場を証明してください。事実と証拠だけが機能します。

于 2010-02-10T08:56:35.857 に答える
3

人をポインターに変えます。それらがクラスhumanへのポインタであり、関数'RemoveCoat'を呼び出していることを伝えます。彼らが人を指して「RemoveCoat」と言っているときは、すべて問題ありません。その人がコートを持っていなくても、心配する必要はありません。私たちはそれをチェックします。RemoveCoatが実際に行うのは、衣類の最上層を取り除くことだけです(品位チェックを使用)。

今、彼らがランダムな場所を指していて、RemoveCoatと言った場合はどうなりますか?壁を指している場合は塗料が剥がれる可能性があり、木を指している場合は樹皮が剥がれる可能性があり、犬は自分自身を剃る可能性があります、USSエンタープライズは重要な瞬間などにシールドを下げてください!

その状況で動作が定義されていない場合に何が起こるかを理解する方法はありません。これは未定義動作と呼ばれ、回避する必要があります。

于 2012-05-29T14:24:31.847 に答える
2

new、new []、delete、delete []を静かにオーバーライドし、彼が気付くのにかかる時間を確認します;)

それが失敗した場合は...彼が間違っていることを伝え、C++仕様に向けてください。そうそう..そして次回は、穴を避けるために人を雇うときはもっと注意してください!

于 2010-02-10T09:05:14.447 に答える
2

1つは...

「この」使用法は言語の一部ではありません。この場合、コンパイラがクラッシュするコードを生成する必要があると言えば、それは機能であり、コンパイラの製造元にとってはある種の要件です。この規格の作成者は、サポートされていない「機能」について不要な作業を行うことを望んでいませんでした。そのような場合、彼らは行動上の要件を作らないことに決めました。

于 2010-02-10T09:12:11.650 に答える
2

私はこの引用が好きです:

未定義の動作:ファイルが破損したり、ディスクがフォーマットされたり、嫌がらせメールが上司に送信されたりする可能性があります。

これを誰に帰するのかわかりません(おそらくEffective C ++からのものです)?

于 2010-02-10T10:00:38.667 に答える
2

C ++は実際にはディレタントのための言語ではありません。いくつかのルールをリストアップし、それらを問​​題なく従わせるだけで、ひどいプログラマーになります。私が人々が言うのを見る最も愚かなことのほとんどは、おそらくこの種の盲目的な規則に従う/弁護士に関係しているでしょう。

一方、デストラクタが呼び出されないこと、およびおそらく他の問題が発生することがわかっている場合は、それを回避するように注意します。さらに重要なことは、偶然にデバッグした場合にデバッグする機会があり、C++の機能の多くがどれほど危険であるかを理解する機会があることです。

心配することがたくさんあるので、単一のコースや本で誰かがC ++をマスターしたり、おそらくそれでそれほど上手になったりすることはありません。

于 2010-02-10T10:44:41.967 に答える
1

Valgrindを見せてください。

于 2010-02-10T09:52:50.310 に答える
1

このプログラムをコンパイルして実行します。

#include <iostream>

class A {
    public:
            A() { std::cout << "hi" << std::endl; }
            ~A() { std::cout << "bye" << std::endl; }
};

int main() {
    A* a1 = new A[10];
    delete a1;

    A* a2 = new A[10];
    delete[] a2;
}

少なくともGCCを使用している場合は、単一の削除を実行するときに、デストラクタが要素の1つに対してのみ呼び出されることを示しています。

PODアレイでの単一削除について。C ++ FAQを紹介するか、cppcheckを使用してコードを実行してもらいます。

于 2010-02-10T10:42:49.740 に答える
1

未定義の動作についてまだ言及されていない1つのポイントは、何らかの操作を実行すると未定義の動作が発生する場合、標準に準拠した実装が合法的に、おそらく「役立つ」または効率を向上させるために、そのような操作の場合に失敗するコードを生成する可能性があることです試みられました。たとえば、任意のメモリ位置がロックされる可能性があり、ロックされた位置にアクセスしようとすると(ロックを解除する場合を除く)、問題の位置がロック解除されるまで停止するマルチプロセッサアーキテクチャを想像できます。ロックとロック解除が非常に安価である場合(ハードウェアに実装されている場合は妥当)、このようなアーキテクチャは、実装されているため、一部のマルチスレッドシナリオで便利です。x++as(アトミックにxを読み取ってロックし、値を読み取るために1を追加し、アトミックにロックを解除してxを書き込む)は、2つのスレッドが両方x++同時に実行された場合、結果としてxに2を追加することを保証します。提供されたプログラムは、未定義の動作を回避するように作成されています。このようなアーキテクチャは、大きな不格好なメモリバリアを必要とせずに、信頼性の高いマルチスレッドコードの設計を容易にする可能性があります。残念ながら、のようなステートメントは、とが両方とも同じ格納場所への参照であり、コンパイラがコードをとしてパイプライン化しようとした*x++ = *y++;場合にデッドロックを引き起こす可能性があります。コンパイラーは、さまざまな操作のインターリーブを控えることでデッドロックを回避できますが、そうすると効率が低下する可能性があります。xyt1 = read-and-lock x; t2 = read-and-lock y; read t3=*t1; write *t2=t3; t1++; t2++; unlock-and-write x=t1; write-and-unlock y=t2;

于 2011-11-20T19:46:39.123 に答える
0

malloc_debugとdeleteデストラクタを含むオブジェクトの配列をオンにします。freeブロック内でポインタを使用すると失敗するはずです。それらをすべて一緒に呼び出して、これを示します。

彼らが初心者であり、C ++について知っておくべきことがたくさんあることを彼らが理解するまで、あなたはあなたの信頼を築くために他の例を考える必要があるでしょう。

于 2010-02-10T09:06:13.000 に答える
0

標準と、標準に準拠するためのツールの開発方法について説明します。UBである、標準外のものは機能する場合と機能しない場合があります。

于 2010-02-10T09:08:56.597 に答える
0

彼らのプログラムが機能しているように見えるからといって、何も保証されません。コンパイラは、平日は機能するコードを生成できますが(正しい動作が定義されていない場合、どのように「機能」を定義しますか?)、週末はディスクをフォーマットします。彼らは彼らのコンパイラにソースコードを読みましたか?それらの分解された出力を調べますか?

または、今日「機能する」という理由だけで、コンパイラのバージョンをアップグレードしたときに機能することを保証するものではないことを彼らに思い出させてください。そこから忍び寄る微妙なバグを見つけるのを楽しんでもらうように彼らに伝えてください。

そして、本当に、なぜですか?それらは、未定義の動作を使用するための正当な議論を提供する必要があり、その逆ではありません。delete怠惰delete[]以外に使用する理由は何ですか?(わかりましstd::auto_ptrた。ただし、 -allocated配列を使用std::auto_ptrしている場合は、とにかく使用する必要があります。)new[]std::vector

于 2010-02-10T12:51:00.897 に答える
0

C標準とC++標準はどちらも、「未定義動作」という用語を使用して、異なる実装が異なる、互換性のない方法で構成を処理するのに役立つ可能性がある状況を指します。その一部は予測どおりに動作しますが、そうでない場合もあります。どちらもUBを説明するために同じ用語を使用しており、公開されているC ++標準の理論的根拠はわかりませんが、C標準の理論的根拠は次のように述べています。

未定義の動作は、診断が難しい特定のプログラムエラーをキャッチしないように実装者にライセンスを与えます。また、準拠する可能性のある言語拡張の領域を識別します。実装者は、公式に定義されていない動作の定義を提供することにより、言語を拡張できます。」

C標準によって未定義動作として分類された多くのアクションは、すべてではないにしても多くの実装で完全に定義されていると見なされましたが、標準の作成者は、異常なプラットフォームまたはアプリケーションフィールドを対象とする実装者に、通常の動作から逸脱する機能を提供したいと考えていました。そうすることは彼らの顧客に利益をもたらすでしょう。このような自由は、プログラマーが必要なことを迅速かつ簡単に行うことを困難にする、前例からの恣意的で気まぐれな逸脱を招くことを意図したものではありません。

残念ながら、gccとclangを使用する多くのプログラマーは、それらのコンパイラーのニーズと同様に、それらのコンパイラーのメンテナーを理解していません。または、悪意のあるプログラムでさえ何も損傷しないコンテキストでのみ実行されます。つまり、プログラマーが他のコンテキストでの使用に適したプログラムを簡単かつ効率的に作成できるようにするための実装は必要ありません。

于 2020-02-15T21:01:23.083 に答える