-1

重複の可能性:
nullインスタンスでメンバー関数を呼び出すと、未定義の動作が発生するのはいつですか?

このようなもの:

class Class {
public:
    void Method()
    {
       //empty;
    }
};

Class* object = 0;
object->Method();

nullポインタを介して非静的メンバー関数を呼び出すことは形式的に違法であるため、C++では未定義の動作です。C ++標準からの引用でいっぱいの詳細な説明については、この回答を参照してください。私は理論的な部分をよく知っています、そしてこの質問は理論についてではないので、それはその質問の複製ではありません。

すべての実装で、上記のコードまたはそれに相当するものが観察可能な問題を引き起こさないことを認識しています。メンバー関数がオブジェクトにアクセスしないため、メソッドは問題なく呼び出されます。

同じ設定で実際に観察可能な問題が発生する実際の例はありますか?

4

3 に答える 3

4

単純:

struct Object { void foo(); std::string s; };

void print(Object* o) {
  o->foo();
  if (o) { std::cout << o->x << "\n"; }
}

(すなわち)fooの非静的属性にアクセスしないとしましょう。Objectx

問題は、 nullの場合、正式に o->foo()は未定義の動作であるためo、nullではないことは明らかですo。したがって、チェックは冗長です。

したがって、関数は最適化されます。

void print(Object* o) {
  o->foo();
  std::cout << o->x << "\n";
}

順序を逆にしても何も変わりません。

void print(Object* o) {
  if (o) { std::cout << o->x << "\n"; }
  o->foo();
}

まだ最適化されています:

void print(Object* o) {
  std::cout << o->x << "\n";
  o->foo();
}

一部のSOメンバーは、未定義動作のタイムトラベル条項と呼ばれることもあります。

詳細については、未定義動作に関するChrisLattnerのシリーズをご覧ください。

あなたの特定の懸念はで扱われ2/3ます。

これが実際に失敗するかどうかは、使用するコンパイラー、指定する最適化パス、およびそれらが実行される順序によって異なります。

あなたは本当にそのすべてに依存したいですか:x?

もちろん、オブジェクトのどの状態にもアクセスしない関数メンバーを持つことは無意味であると主張するでしょう...したがって、質問自体は実際にはほとんど価値がありません(しかし、その理論的側面では興味深いです)。

于 2012-02-08T10:15:08.147 に答える
1

これはUBですが、何が「問題」になるのでしょうか。問題になるには、コードは、標準が実行する必要があると私たちが期待すること以外のことを実行する必要があります。そうでなければ、問題ではありません。標準では、コードが何をすべきか、または何をするかはわかりません。したがって、コードが何をするにしても問題はありません。

あなたはそれが「観察可能な問題」を引き起こさないと言います。もちろん、そうではありません。それが何をしたとしても大丈夫でしょう。それは失敗する可能性があり、それは「問題」ではありません。それは、標準が私たちに起こり得ると言っていることだからです。

于 2012-02-08T10:19:52.157 に答える
0

このコードが、私が知っているプラ​​ットフォームで問題を引き起こす可能性はほとんどありません。これは、主に無関係なコーナーケースであるため、未定義の動作です。特定の条件下では、nullポインターでメンバー関数を呼び出しても問題ないと定義できます。しかし、ポイントは何ですか?どのメンバーにもアクセスしない場合、なぜその関数を非静的メンバー関数にするのですか?このケースを定義する必要は考えられないため、これを未定義のままにしておくことに損失はありません。したがって、言語が不必要に複雑になります。

于 2012-02-08T10:13:15.137 に答える