C++ 里 delete 指针两次会怎么样?

初学 C++,书上说会很严重。
关注者
487
被浏览
314,466

60 个回答

你倒是试试啊!!!!!

============================

由于知乎的评论框功能非常少,所以

@可知不可知

的讨论我塞在这里。

首先:

作为类的设计者,你根本不知道类的使用者会如何使用你的类。

完全相反,你必须 限定 使用者如何使用你的设施,特别是涉及到所有权问题的时候。比如C++标准库的容器,特别是string和vector,都有返回内部数据的方法(c_str()和data())。显然用户是 不能 delete或者free这个数据的。这就是一个限定,而且和你所讨论的情景非常相似。

再比如GNU Glib:

gchar *
g_strdup_printf (const gchar *format,
                 ...);
Similar to the standard C sprintf() function but safer, since it calculates the maximum space required and allocates memory to hold the result. The returned string should be freed with g_free() when no longer needed.

这里,返回的数据是有用户持有的。用户 必须 在用完之后亲自删除这个数据,否则就会泄露。

然后,你在设计接口的时候,必须想好它的行为,或者说,用户使用这个接口时的可能性。对于你的示例:

class Test
public:
    int * p;
    Test() : p(new int(22)){}
    ~Test(){delete p; p = nullptr;}
    void func()
        delete p;
        p = nullptr; // 去掉则报错
};

实际上应当设计成这样:

class Test
public:
    Test() : p(new int(22)){}
    ~Test(){delete p;} // 没有必要在此设置nullptr。
    void release_resource()
        debug_assert(p != nullptr); // 如果你不想允许多次调用,就限定它。
        delete p;
        p = nullptr; // 标明一项资源的状态为空。
    void some_function_that_use_p()
        debug_assert(p != nullptr);
        // code that use p
private:
    int* p;
};

和题目不是太相关,

@可知不可知

@叛逆者

都给出了delete后一定要置空指针的建议,很怕这种观念又成为了某种教条。

举个例子:

~scoped_ptr() // never throws
#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
        boost::sp_scalar_destructor_hook( px );
#endif
        boost::checked_delete( px );

这是boost::scoped_ptr的实现,checked_delete只是增加了对incomplete type的检查:

template<class T> inline void checked_delete(T * x)
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);