有些程序员喜欢在释放指针后将指针变量设置为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();
}
}
答案 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 new
和operator 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