我如何知道指针是否已通过"新建"分配数据?

How do I know if a pointer has been assigned data via 'new'?

本文关键字:新建 分配 数据 已通过 何知道 指针 是否      更新时间:2023-10-16

假设我有一个这样的指针:

int *thingy;

在某个时刻,这个代码可能被调用,也可能不被调用:

thingy=new int;

我如何知道我是否能做到这一点:

delete thingy;

我可以为每个指针使用bool,并在每次使用new时将布尔标记为true,但我有很多指针,这会变得非常困难。

如果我没有在thingy上调用new,那么在它上面调用delete可能会导致崩溃,对吧?

我找了很多遍,但都找不到符合我情况的答案。

编辑:我需要能够随心所欲地delete指针,而指针不必指向任何数据。如果这是不可能的,我将不得不重新编写我的代码。

将其初始化为NULL始终

int *thingy = NULL;

然后

delete thingy;
thingy = NULL;

即使thingy为NULL也有效。只要thingyNULLdelete就不会有不必要的副作用,你可以随心所欲地删除。

没有内置的方法来判断特定的指针值是否可以delete。相反,你只需要设计程序来做正确的事情,最好是根据你的需求仔细设计资源所有权政策,并用RAII之类的东西来实施。

给定适当的RAII类型,就不需要在代码中散布delete或其他资源管理命令。您只需初始化并使用适当类型的对象,并将清理留给对象本身。例如,如果RAII类型unique_ptr对应于您想要使用的所有权策略,那么您可以通过以下方式管理对象:

unique_ptr<int> thingy {new int};
// use thingy ...

不需要手动清理,因为unique_ptr会为您处理这些问题。

另一方面,如果你试图直接管理资源,你最终会得到很多代码,比如:

int *thingy = nullptr;
// ...
thingy = new int;
try {
    // something that might throw
} catch(...) {
    delete thingy;
    thingy = nullptr;
    throw;
}
delete thingy;
thingy = nullptr;

没有内置的C++工具来识别指针是否指向堆数据,并且可以安全地deleted。删除NULL指针是安全的,并且可以将数据已删除的每个指针设置为NULL。但这无助于区分指向堆数据的指针和指向其他数据或代码的指针。

当您的操作系统启动一个进程时,它会将代码和数据部分定位到特定的数据区域。在Windows中,这部分由EXE文件的PE头控制。因此,存储器区域的实际地址可以变化。但你可以确定这些区域的位置:

  • 代码
  • bss
  • 数据
  • 烟囱

在获得每个区域的地址范围后,您可以区分指向堆数据的指针(在适合删除的情况下(和指向堆栈数据的指针。这允许您区分delete表和指针不能删除的数据。

编写一个为您进行跟踪的包装类,例如:

template<typename T>
class ptr_t
{
private:
    T* m_ptr;
    bool m_delete;
    ptr_t(const ptr_t&) {}
    ptr_t& operator=(const ptr_t&) { return *this; }
public:
    ptr_t()
        : m_ptr(NULL), m_delete(false)
    {
    }
    ptr_t(T *ptr, bool del)
         : m_ptr(ptr), m_delete(del)
    {
    }
    ~ptr_t()
    {
       reset();
    }
    void assign(T *ptr, bool del)
    {
        if (m_delete)
            delete m_ptr;
        m_ptr = ptr;
        m_delete = del;
    }
    void reset()
    {
        assign(NULL, false);
    }
    operator T*() { return m_ptr; }
    bool operator!() const { return (!m_ptr); }
};
typedef ptr_t<int> int_ptr;

int_ptr thingy;
...
thingy.assign(new int, true);
...
thingy.reset();

int i;
int_ptr pi;
...
pi.assign(&i, false);
...
pi.reset();