6

有人可以向我解释为什么这段代码只打印“42”而不是“created\n42”吗?

#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

因为它表现出未定义的行为 - 您取消引用空指针。

当你说:

 auto_ptr<MyClass> ptr;

你创建了一个不指向任何东西的自动指针。这相当于说:

MyClass * ptr = NULL;

然后当你说:

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

你取消引用这个空指针。这样做在 C++ 中是未定义的 - 对于您的实现,它似乎有效。

于 2009-07-18T19:16:31.593 回答
21

std::auto_ptr不会自动为您创建对象。也就是说,就目前而言, ptrmain 被初始化为 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

首先,请记住,->运算符 ofauto_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 回答