2

考虑以下 c++ 代码:

class test
{
public:
    int val;

    test():val(0){}
    ~test()
    {
        cout << "Destructor called\n";
    }
};

int main()
{
    test obj;
    test *ptr = &obj;
    delete ptr;

    cout << obj.val << endl;

    return 0;
}

我知道 delete 应该只在动态分配的对象上调用,但现在 obj 会发生什么?

好的,我知道我们不应该做这样的事情,现在如果我正在编写智能指针的以下实现,我怎么能确保这样的事情不会发生。

class smart_ptr
{
public:
    int *ref;
    int *cnt;

    smart_ptr(int *ptr)
    {
        ref = ptr;
        cnt = new int(1);
    }

    smart_ptr& operator=(smart_ptr &smptr)
    {
        if(this != &smptr)
        {
            //  House keeping
            (*cnt)--;
            if(*cnt == 0)
            {
                delete ref;
                delete cnt;
                ref = 0;
                cnt = 0;
            }

            //  Now update    
            ref = smptr.ref;
            cnt = smptr.cnt;
            (*cnt)++;
        }
        return *this;
    }

    ~smart_ptr()
    {
        (*cnt)--;
        if(*cnt == 0)
        {
            delete ref;
            delete cnt;
            ref = 0;
            cnt = 0;
        }
    }
};
4

5 回答 5

3

您在帖子中提出了两个不同的问题。我将分别回答他们。

但是现在 obj 会发生什么?

你的程序的行为是未定义的。C++ 标准没有对现在发生的事情发表评论obj。事实上,该标准也没有评论您的程序在错误之前所做的事情。它根本没有定义

也许您的编译器供应商对发生的事情做出了承诺,也许您可​​以检查程序集并预测会发生什么,但是 C++本身并没有定义会发生什么。

实际上说1,您可能会从标准库中收到警告消息,或者您会收到段错误,或两者兼而有之。

1:假设您在 Windows 或带有 MMU 的类 UNIX 系统中运行。其他规则适用于其他编译器和操作系统。


我怎样才能确保 [ deleteing a stack variable] 不会发生。

smart_ptr切勿使用堆栈变量的地址进行初始化。一种方法是将接口记录到smart_ptr. 另一种方法是重新定义接口,以便用户永远不会将指针传递给smart_ptr; makesmart_ptr负责调用new.

于 2012-11-20T16:56:52.693 回答
1

您的代码具有未定义的行为,因为您在未分配 new 的指针上使用了 delete。这意味着任何事情都可能发生,并且不可能说会发生什么obj

猜想在大多数平台上你的代码会崩溃。

于 2012-11-20T16:57:00.103 回答
1

Delete 试图访问内存中的 obj 空间,但操作系统不允许这样做并抛出(核心转储)异常。

于 2012-11-20T17:00:30.633 回答
0

不确定会发生什么,所以你不能说太多。您能做的最好的事情就是推测特定的实现/编译器。

于 2012-11-20T16:56:48.590 回答
0

这不仅仅是未定义的行为,就像其他答案中所说的那样。这几乎肯定会崩溃。

第一个问题是尝试释放堆栈变量。

第二个问题将在程序终止时发生,此时test将调用析构函数obj

于 2012-11-20T17:01:56.167 回答