是否有已发布指针的已建立指针值?

时间:2011-01-20 11:43:44

标签: c++ visual-studio-2008 debugging pointers memory-management

有些程序员喜欢在释放指针后将指针变量设置为null:

delete ptr;
ptr = 0;

如果有人试图再次发布指针,则不会发生任何事情。在我看来,这是错误的。在指针被释放后访问指针是一个错误,错误应尽快跳到你的脸上。

我是否可以为指定已发布的指针的指针变量分配一个替代值?

delete ptr;
ptr = SOME_MAGIC_VALUE;

理想情况下,我希望Visual Studio 2008告诉我“程序已经终止,因为你试图在调试模式下访问已发布的指针!”。


好吧,我似乎必须自己做检查。以下模板有什么问题吗?

template <typename T>
void sole_delete(T*& p)
{
    if (p)
    {
        delete p;
        p = 0;
    }
    else
    {
        std::cerr << "pointee has already been released!\n";
        abort();
    }
}

12 个答案:

答案 0 :(得分:7)

没有。如果你真的想警告或错误的话,在尝试delete某事时测试为“0”。

或者,在开发过程中,您可以省略ptr = 0;并依靠valgrind告诉您何时何地尝试双重免费。请务必将ptr = 0;重新发布。

修改是的,我知道的人 C ++不需要围绕delete 0进行测试;

我不是在暗示if (ptr != 0) delete ptr;。我建议if (ptr == 0) { some user error that the OP asked for } delete ptr;

答案 1 :(得分:5)

释放指针后分配NULL。在使用之前,检查以查看其NULL ..如果为空,请自行报告错误

答案 2 :(得分:4)

  

我是否可以为指定已发布的指针的指针变量分配一个替代值?

     

理想情况下,我希望Visual Studio 2008告诉我“程序已经终止,因为你试图在这里访问已经发布的指针!”在调试模式下。

只需执行delete ptr即可实现这一目标。如果双重删除此指针,运行时将捕获您。

无论如何,在过去十年中,我认为我已经写过ptr = NULL多次。我为什么要这样做?这样的指针肯定隐藏在一个对象中,该对象的析构函数将删除它引用的对象,并且在调用析构函数之后,指针也会消失。

如果某些情况需要我在指针被删除后留下指针,我不会将其设置为NULL只是因为 我希望代码能够崩溃 如果我要双重删除的话。将指针设置为NULL只需 即可屏蔽错误

当然,所有这些并不意味着人们不希望指针明确设置为“无”,并使用NULL。但是不要屏蔽双删除错误。

答案 3 :(得分:2)

不,从C ++的角度来看,在空指针上调用delete是完全正常的。分配一些魔法值会严重破坏代码 - 你现在必须区分空指针,有效指针和魔术值指针,我想这将是一个巨大的混乱。

如果你真的反对删除空指针,你可以有一个单独的布尔标志和每个指针,意味着它已经是delete d。也许你可以为它编写一个包装类。

答案 4 :(得分:2)

如果您只想检查分配和删除,最简单的方法是编写自己的全局operator newoperator delete,并手动跟踪分配和解除分配的所有指针。

当然,您也可以使用现有的工具为您做到这一点,例如: Valgrind的。

如果你还希望协议每个指针访问,这会变得毛茸茸。您基本上必须修补可执行文件或在虚拟机中执行它,其中每个指针访问都被重定向到您的簿记例程。

但是再一次,像Valgrind这样的现有工具已经为你做到了。对于Valgrind,您的可执行文件在虚拟机中运行;其他程序通过修改字节代码来修补应用程序。

答案 5 :(得分:1)

当您在调试模式下删除指针时,许多编译器会使用一些值绘制字节,以便在您尝试读取时将内存指示为“无效”。当然,真正的内存可能有这些字节,因此它会分配一些额外的内容来指示您正在读取的指针是否有效,并绘制您不能直接访问的字节。

在同一个指针(变量)上多次调用delete只是在它指向的位置上没有错。

也许这不是最好的方法,但它当然完全合法......

T * array[N];
for( i = 0; i < N; ++ i )
{
   array[i] = new T;
}
T* ptr;
for( i = 0; i < N; ++i )
{
  ptr = array[i];
  delete ptr;
}

除了不是最好的做事方式之外,我在变量“ptr”上多次调用delete,但是在不同的地址上,显然不是错误。

答案 6 :(得分:1)

回答有问题的问题[原文如此]。

不,发布的指针没有确定的值。

我认为应该注意对无效指针(如NULL)的任何访问 - 不仅要在释放后访问它们,如果没有(非NULL)初始化发生,这可能永远不会发生。当您尝试访问空指针时,调试器必然会发出警告 - 如果没有,则不应该使用它。

编辑:回答原始问题的结束;关于双重删除

如果delete上的NULL是一个等待发生的错误,那么这取决于设计。在许多情况下,事实并非如此。也许您应该在需要时使用“安全删除” - 或者在调试时使用?像这样:

template <typename T>
void safe_delete(T*& ptr)
{
  if (ptr == 0)
    throw std::runtime_error("Deleting NULL!");
  delete ptr;
  ptr = 0;
}

答案 7 :(得分:1)

我认为尖锐的already provided a valid answer,但我认为他没有明确说出来:

如果 你的 代码在通过该指针变量删除其对象后访问指针变量时出错,那么 < strong>你 必须自己添加一些检查。(可能是通过一些标志。)

答案 8 :(得分:1)

没有意义。

我不会进入显然相当热门的对话,只是指出一个明显的事实:指针通过副本传递

使用一些代码,它会给出:

T* p = /* something */;
T* q = p;

delete q;
q = 0;

你觉得安全吗?

问题是你无法确保你的魔法值已经传播到所有指向对象的指针。

这就像在筛子上堵一个洞,希望它能阻止水倒出。

答案 9 :(得分:0)

在C ++ 0x中,您可以

delete ptr;
ptr = nullptr;

答案 10 :(得分:0)

将指针设置为特定值只会影响指针的这个副本,因此它几乎不提供任何保护。如果程序需要是可验证的正确的,那么有智能指针类可以跟踪指针的副本并使这些指针无效,否则我只会推荐一个像Valgrind(在Linux上)或Rational Purify(在Windows上)上的工具,它可以让你检查对于内存访问错误。

答案 11 :(得分:0)

delete nullpointer不是错误;根据定义,它什么都不做。

通常,在delete之后将指针变量置空是一个坏主意,因为它唯一可能的效果是隐藏导致多次删除的错误(指针变量为空)第二次删除不起作用,而不是例如崩溃)。

一般来说,在我看来,指针的归零属于所有其他微软主义,如匈牙利表示法和广泛使用的宏。

这可能曾经有过一个很好的理由,但是今天,从2011年起,它只会产生负面影响,并且是出于纯粹的惯性而使用:Knuth曾经为随机生成器描述过的同类传播 - 差不多可能最受欢迎,然后作为默认生成器加入到无数语言实现和库中,大多数人认为广泛使用意味着它必须至少是合理的。

然而,话说回来,对于倾向于超正式迂腐的人来说,至少在情感上令人满意的想法是在在std::vector之后delete。原因是神圣标准ISO / IEC 14882允许std::vector析构函数执行相当不利的事情,例如复制指针值。在正式的迂腐观点中,即使这种无效指针值的复制也会产生未定义的行为。这不是一个实际问题。首先,我知道绝对没有现代平台,其中复制会产生任何不良影响,其次,如此多的代码依赖于标准容器的合理行为,他们只需要:否则,没有人会使用这样的实现。

干杯&amp;第h