6

このコードが「created\n42」ではなく「42」のみを出力する理由を誰か説明してもらえますか?

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class MyClass
{
public:
    MyClass() {cout<<"created"<<endl;};
    int solution() {return 42;}
    virtual ~MyClass() {};
};

int main(int argc, char *argv[])
{
    auto_ptr<MyClass> ptr;
    cout<<ptr->solution()<<endl;
    return 0;
}

ところで、ソリューションでさまざまな値を使用してこのコードを試してみましたが、常に「正しい」値が得られるため、ランダムなラッキー値ではないようです。

4

7 に答える 7

27

未定義の動作を示すため、null ポインターを逆参照します。

あなたが言う時:

 auto_ptr<MyClass> ptr;

何も指さないオートポインターを作成します。これは、次のように言うのと同じです:

MyClass * ptr = NULL;

次に、あなたが言うとき:

cout<<ptr->solution()<<endl;

この null ポインターを逆参照します。それを行うことはC++では定義されていません-実装では、機能しているようです。

于 2009-07-18T19:16:31.593 に答える
21

std::auto_ptrは自動的にオブジェクトを作成しません。つまりptr、main のままでは null に初期化されます。これを逆参照することは未定義の動作であり、たまたま運が良く、結果として 42 が得られます。

実際にオブジェクトを作成する場合:

int main(int argc, char *argv[])
{
    auto_ptr<MyClass> ptr(new MyClass);

    cout << ptr->solution() << endl;

    return 0;
}

期待どおりの出力が得られます。

于 2009-07-18T19:18:19.077 に答える
3

まず、->演算子auto_ptrは基本的に含まれているポインターに転送されることに注意してください。したがって、この議論では、コードはmain次と同等になります。

MyClass* ptr = NULL;
cout << ptr->solution() << endl;

this次に、コンパイラは、別の関数引数として渡されたポインターを持つ非メンバー関数であるかのように機能する方法でメンバー関数を実装する傾向があることに注意してください。したがって、現在のコンパイラの観点からは、コードはmain次のように動作します。

MyClass* ptr = NULL;
cout << solution(ptr) << endl;

ソリューションは次のように記述されます。

int solution(MyClass* this) { return 42; }

その場合、クラッシュが発生しなかった理由が明らかになります。


ただし、他の人が既に述べたように、これらはコンパイラが C++ を実装する方法の内部の詳細であり、言語標準では指定されていません。したがって、理論的には、このコードはあるコンパイラではここで説明されているように機能しますが、別のコンパイラではクラッシュしたり、まったく別のことをしたりする可能性があります。

しかし実際には、標準でこの動作が保証されていなくても、必要に応じて特定のコンパイラで保証できます。たとえば、MFC はこの動作に依存しているため、Visual Studio がサポートを停止する可能性はほとんどありません。もちろん、コードが使用される可能性のある特定のコンパイラをそれぞれ調査して、実際にこの動作が保証されていることを確認する必要があります。

于 2009-07-19T01:24:13.200 に答える
2

あなたは答えに対する質問を知らないから xD

コンストラクターを呼び出していないようですよね?

于 2009-07-18T19:17:01.297 に答える
2

オブジェクトのインスタンスを作成していません。
スマート ポインターを作成しているだけです。

メソッドを呼び出すと、NULL ポインターが逆参照されるため、Neil が述べたように、未定義の動作になります。しかし、あなたのコードはメンバー変数にアクセスしようとしないので、幸運にもクラッシュしません。

これを試して:

auto_ptr<MyClass> ptr(new MyClass);
于 2009-07-18T19:20:54.923 に答える
1

初期化されていないためptr、あなたは幸運です。最初にそれを呼び出す必要がnewあります:

auto_ptr<MyClass> ptr( new MyClass );
于 2009-07-18T19:21:16.933 に答える
1

「ソリューション」メソッドは実際にクラス メンバーを使用する必要がないため、クラッシュすることはありません。メンバーか何かを返す場合は、おそらくクラッシュするでしょう。

于 2009-07-18T19:35:34.177 に答える