この質問の人は、「new」を使用してオブジェクトへのポインターを作成できませんでした。次に、このワイルドポインターを使用して、オブジェクトのメンバー関数を呼び出しました。
メンバー変数にアクセスすると(でmyPoint[i].x = xData;
)、プログラムは失敗します。
それ以前ではなく、その場所で失敗するのはなぜですか?
この質問の人は、「new」を使用してオブジェクトへのポインターを作成できませんでした。次に、このワイルドポインターを使用して、オブジェクトのメンバー関数を呼び出しました。
メンバー変数にアクセスすると(でmyPoint[i].x = xData;
)、プログラムは失敗します。
それ以前ではなく、その場所で失敗するのはなぜですか?
問題の行は、 が参照される最初の位置this
です。
そして、なぜですか?標準では、このプログラムには未定義の動作があると言われていますが、C++ ではクラスに 3 種類の関数があります。
// 1) static functions
class test {
public:
static void foo( int n );
};
この例foo
では、同じシグネチャを持つグローバル関数のようなものですが、C++ ではアクセス チェックとその名前の規則が異なります。
// 2) normal member functions
class test {
public:
void foo( int n );
};
ほとんどすべてのコンパイラでは、この関数は署名付きのフリー関数と同じであり、関数でアクセスしない限りvoid foo(foo* this, int n)
、この関数を無効で呼び出すことはエラーではありません。あなたの記憶の。this
this
// 3) virtual functions
class test {
public:
virtual void foo( int n );
};
この場合class test
、通常呼び出され、クラスvtable
の各関数の実装への 1 つのポインターを含む追加の非表示メンバーが含まれますvirtual
。この手法を使用すると、C++ は実行時に遅延バインディングを行うことができるため、この場合、foo
コンパイラーを呼び出すときに次のように記述します。
this->vtable[foo_index]( this, n );
したがって、この場合、invalidはすぐにそれ自体を表示し、コール ポイントでthis
アクセスするため、セグメンテーション違反や無効な命令などのエラーを生成する可能性があります。this
したがって、ほとんどすべての実装でわかるように、無効なthis
ポインターを介して呼び出され、エラーを生成しないメンバー関数を持つことができます (this
関数内でアクセスしない場合) virtual
。
ただし、上記の説明はコンパイラに完全に依存することを覚えておいてください。ただし、ほとんどすべてのコンパイラは上記のように実装しています。
Undefined Behaviorの詳細を読んで、例に基づいて構築する必要があります。
struct A { A(int i): _i(i) {} void print() const { printf("%d", _i); } int _i; };
void function(A* a) {
if (a == 0) { printf("%s", "A is null!"); }
a->print();
}
あなたは何を期待していますfunction(0);
か?
A is null!
それが印刷されて、プログラムがクラッシュすることを期待しているようですね。多分そうでないかもしれません。
コンパイラは実際には次のように処理を進める可能性があります。
a->print();
:ここにa
あることはできませんnull
。それ以外の場合、このステートメントは無意味ですa == 0
したがって、常にfalse
void function(A* a) { a->print(); }
そして、一般的な Linux プラットフォームでは、クラッシュ (SEGFAULT) が発生しますが、メッセージは表示されません... まったく!
これが、未定義の動作が最適化で行うことです。プログラムははるかに高速に実行されますが、わずかなミスで計り知れない方法で停止します。