1. ホーム
  2. c++

[解決済み】境界外の配列にアクセスしてもエラーにならない、なぜ?

2022-04-08 04:43:11

質問

C++のプログラムで、以下のように境界外の値を代入しています。

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    return 0;
}

プログラムは次のように表示します。 34 . ありえないはずです。 私はg++ 4.3.3を使っています。

以下はコンパイルと実行のコマンドです。

$ g++ -W -Wall errorRange.cpp -o errorRange
$ ./errorRange
3
4

を割り当てる場合のみ array[3000]=3000 を実行すると、segmentation fault が発生します。

gccが配列の境界をチェックしない場合、私のプログラムが正しいかどうか、後で深刻な問題につながる可能性があるので、どうしたら確認できますか?

上記のコードを

vector<int> vint(2);
vint[0] = 0;
vint[1] = 1;
vint[2] = 2;
vint[5] = 5;
cout << vint[2] << endl;
cout << vint[5] << endl;

で、こちらもエラーは出ません。

解決方法は?

C/C++プログラマの最良の友へようこそ。 未定義の動作 .

さまざまな理由から、言語規格で規定されていないことがたくさんあります。これもそのひとつです。

一般に、未定義の動作に遭遇したときはいつでも 何でも が起こるかもしれません。アプリケーションがクラッシュしたり、フリーズしたり、CD-ROMドライブが取り出されたり、鼻から悪魔が出たりするかもしれません。ハードディスクをフォーマットしたり、おばあちゃんにポルノを全部メールで送ったりするかもしれません。

本当に運が悪いと、こんなこともあるかもしれません。 現れる は正しく動作します。

この言語は単純に、以下の要素にアクセスした場合に何が起こるべきかを述べています。 内の 配列の境界。境界からはみ出したらどうなるかは未定義です。もしかしたら と思われる しかし、これは合法的なCやC++ではありませんし、次にそのプログラムを実行したときにまだ動くという保証はありません。あるいは、現在でも必要なデータが上書きされておらず、問題に遭遇していないだけで、そのプログラムが を引き起こします。

については なぜ を使用した場合、境界チェックが行われないため、その答えにはいくつかの側面があります。

  • 配列はC言語の名残で、C言語の配列は原始的と言えるでしょう。連続したアドレスを持つ要素の列です。単に生のメモリを公開しているだけなので、境界チェックはありません。堅牢な境界チェック機構を実装することは、C言語ではほとんど不可能だったでしょう。
  • C++では、クラス型に対して境界チェックが可能です。しかし、配列はまだC互換のプレーンなものだ。クラスではありません。さらに、C++は、境界チェックを非理想的なものにする別のルールの上に成り立っている。C++の指針は、"you don't pay for what you don't use"(使わないものにはお金を払わない)だ。コードが正しければ、境界チェックは必要ありませんし、実行時の境界チェックのオーバーヘッドにお金を払うことを強制されるべきでもありません。
  • そこでC++では std::vector クラスのテンプレートで、両方を可能にします。 operator[] は効率的であるように設計されています。言語規格では、境界チェックを行うことは要求されていない(禁止もされていない)。また,ベクトルには at() メンバー関数 が保証されている で境界チェックが行われます。つまり、C++では、ベクターを使えば、両方の長所を得ることができるのです。C++では、ベクトルを使えば、境界チェックをせずに配列のようなパフォーマンスを得ることができます。 必要なときに境界チェックされたアクセスを使用することができます。