7

コンパイル時にエラーが発生しないのはなぜですか?

#include <iostream>
using namespace std;

int main()
{
    int *a = new int[2];
    // int a[2]; // even this is not giving error
    a[0] = 0;
    a[1] = 1;
    a[2] = 2;
    a[3] = 3;
    a[100] = 4;
    int b;

    return 0;
}

誰かがこれが起こっている理由を説明できますか?前もって感謝します。)

4

4 に答える 4

12

未定義の振る舞い==何でも起こり得るからです。クラッシュしないのは不幸です。この種の動作は潜在的にバグを隠す可能性があります。

2回定義することに関しては、これaはコンパイラのバグです。

于 2012-09-13T15:43:04.533 に答える
10

確かに呼び出される2つの変数を宣言aすることはエラーです。コンパイラがそれを受け入れる場合、それは壊れています。ある宣言を別の宣言に置き換えても、エラーが発生しないことを意味していると思います。

配列アクセスは範囲チェックされません。コンパイル時には、配列のサイズがわからないことが多く、言語がわかっていてもチェックする必要はありません。実行時に、チェックによってパフォーマンスが低下し、不要なものにお金を払わないというC++の哲学に反します。したがって、配列の終わりを超えてアクセスすると、未定義の動作が発生します。それが発生しないようにするのはプログラマーの責任です。

無効なアクセスによってセグメンテーション違反が発生する場合がありますが、これは保証されていません。通常、メモリ保護はメモリのページ全体にのみ適用され、通常のページサイズは数キロバイトです。有効なメモリのページ内のアクセスはキャッチされません。アクセスするメモリに他のプログラム変数または呼び出しスタックの一部が含まれている可能性が高いため、そこに書き込むと、想像できるほぼすべての方法でプログラムの動作に影響を与える可能性があります。

安全を確保したい場合は、を使用し、その関数std::vectorを使用してその要素にのみアクセスできます。at()これにより、インデックスがチェックされ、範囲外の場合は例外がスローされます。また、メモリ割り当てを管理し、例のメモリリークを修正します。

于 2012-09-13T15:53:46.533 に答える
5

あなたはJavaまたはJavaに似た言語から来ていると思います。配列の境界から外れると、「配列のインデックスが範囲外」という例外が発生します。

ええと、Cはあなたにもっと期待しています。それはあなたが要求するスペースを節約しますが、あなたがその節約されたスペースの境界の外に出ているかどうかをチェックしません。上記のようにこれを行うと、プログラムはその恐ろしい未定義の動作をします。

また、将来的には、プログラムにバグがあり、それを見つけることができないようで、コードを調べたりデバッグしたりすると、すべて問題ないように見えることを忘れないでください。境界」と未割り当ての場所へのアクセス。

于 2012-09-13T16:45:11.320 に答える
0

優れたコード分析を備えたコンパイラーは、配列の割り当てを超えてそのコードを参照していることを確実に警告します。複数の宣言を忘れて、それを実行した場合、それは失敗するかもしれないし、失敗しないかもしれません(他の人が言っているように未定義の振る舞い)。たとえば、(プロセッサアドレス空間に)4KBページのヒープを取得した場合、そのページの外部に書き込みを行わなければ、プロセッサから障害が発生することはありません。配列の削除時に、それを実行した場合、およびヒープの実装によっては、ヒープが破損していることを検出する場合があります。

于 2012-09-13T17:26:24.673 に答える