指针是否保证在C ++中的`delete`后保留其值?

时间:2023-01-22 17:14:28

Inspired by this question.

灵感来自这个问题。

Suppose in C++ code I have a valid pointer and properly delete it. According to C++ standard, the pointer will become invalid (3.7.3.2/4 - the deallocation function will render invalid all pointers referring to all parts of deallocated storage).

假设在C ++代码中我有一个有效的指针并正确删除它。根据C ++标准,指针将变为无效(3.7.3.2/4 - 释放函数将使所有指向无法释放存储的所有部分的指针无效)。

At least in most implementations it preserves the value and will store exactly the same address as before delete, however using the value is undefined behavior.

至少在大多数实现中,它保留了值并将存储与删除之前完全相同的地址,但是使用该值是未定义的行为。

Does the standard guarantee that the pointer will preserve its value or is the value allowed to change?

标准是否保证指针将保留其值或允许更改的值?

7 个解决方案

#1


19  

No, it's not guaranteed and an implementation may legitimately assign zero to an lvalue operand to delete.

不,它不能得到保证,并且实现可以合法地将零值分配给要删除的左值操作数。

Bjarne Stroustrup had hoped that implementations would choose to do this, but not many do.

Bjarne Stroustrup曾希望实现会选择这样做,但并不是很多。

http://www.stroustrup.com/bs_faq2.html#delete-zero

#2


10  

If, for whatever reason, you want to be sure the pointer variable is not changed by delete, write:

无论出于何种原因,如果要确保删除不改变指针变量,请写:

delete p + 0;

#3


3  

I believe that most implementations will keep the value, only for the sake of having no reason to change it. But regardless of whether the value is kept, it's still a useless pointer, is it not?

我相信大多数实现都会保留价值,只是为了没有理由改变它。但无论值是否保留,它仍然是一个无用的指针,不是吗?

#4


2  

The signature of the global operator delete, as required by the standard 3.7.3.2/2:

根据标准3.7.3.2/2的要求,全局运算符的签名删除:

Each deallocation function shall return void and its first parameter shall be void*.

每个释放函数都应返回void,其第一个参数应为void *。

This means that delete cannot modify the pointer you pass to it, and it will always retain its value.

这意味着删除不能修改传递给它的指针,它将始终保留其值。

#5


1  

Consider, how would you check or rely on any "yes" or "no" answer? You can't. Or, you can, but the result of that checking (except for nullpointer) is Undefined Behavior.

考虑一下,您如何检查或依赖任何“是”或“否”的答案?你不能。或者,您可以,但检查的结果(nullpointer除外)是未定义的行为。

You can't check a non-null value after a delete, so the question is in general meaningless.

删除后无法检查非空值,因此问题通常无意义。

Also, the argument to delete can be an rvalue expression, so the question is meaningless.

此外,删除的参数可以是右值表达式,因此问题毫无意义。

Cheers & hth.,

干杯&hth。,

#6


1  

A pointer is not guaranteed to be of any meaningful value in of itself other than the range in which it was allocated and one past the end of that range.

除了分配指针的范围和超出该范围结束的指针之外,不保证指针本身具有任何有意义的值。

What you might be questioning is whether, say, you were doing your own leak checking so you wrote function to remove a pointer from a map after you had done a delete. That would use std::less which is guaranteed to work with pointers that do not point within a range, and would presumably work too with pointers that pointed to memory that is no longer valid.

您可能会质疑的是,您是否正在进行自己的泄漏检查,因此您在完成删除后编写了从地图中删除指针的功能。这将使用std :: less,它可以保证与指向范围内的指针一起使用,并且可能也会使用指向不再有效的内存的指针。

Of course you might get your garbage collecting to do the "remove" just before deleting the memory it was pointing to.

当然,在删除它指向的内存之前,你可能会收集垃圾进行“删除”。

As it is with the standard, if the value you pass to delete is not an l-value it is guaranteed to maintain the same value, but if it is an l-value it is implementation defined.

与标准一样,如果传递给delete的值不是l值,则保证保持相同的值,但如果它是l值,则它是实现定义的。

#7


1  

This question is important! I have seen that Visual Studio 2017 has changed pointer value after "delete". It coused a problem because I has using memory tracing tool. The tool was collecting pointers after each operator "new" and was checking them after "delete". Pseudo code:

这个问题很重要!我已经看到Visual Studio 2017在“删除”之后更改了指针值。它因为我使用了内存跟踪工具而引发了一个问题。该工具在每个操作符“new”之后收集指针,并在“删除”之后检查它们。伪代码:

Data* New(const size_t count)
{
    Data* const ptr(new Data[count]);
    #ifdef TEST_MODE
    DebugMemory.Collect(ptr);
    #endif
    return ptr;
}

void Delete(Data* const ptr)
{
    delete[] ptr;
    #ifdef TEST_MODE
    DebugMemory.Test(ptr);
    #endif
}

This code works good on Visual Studio 2008 but was failing on Visual Studio 2017 so I have changed the order of operations in second function.

此代码在Visual Studio 2008上运行良好但在Visual Studio 2017上失败,因此我更改了第二个函数中的操作顺序。

However The question is good and the problem exists. Experienced engineers should be aware of that.

但问题是好的,问题就存在了。有经验的工程师应该意识到这一点。

#1


19  

No, it's not guaranteed and an implementation may legitimately assign zero to an lvalue operand to delete.

不,它不能得到保证,并且实现可以合法地将零值分配给要删除的左值操作数。

Bjarne Stroustrup had hoped that implementations would choose to do this, but not many do.

Bjarne Stroustrup曾希望实现会选择这样做,但并不是很多。

http://www.stroustrup.com/bs_faq2.html#delete-zero

#2


10  

If, for whatever reason, you want to be sure the pointer variable is not changed by delete, write:

无论出于何种原因,如果要确保删除不改变指针变量,请写:

delete p + 0;

#3


3  

I believe that most implementations will keep the value, only for the sake of having no reason to change it. But regardless of whether the value is kept, it's still a useless pointer, is it not?

我相信大多数实现都会保留价值,只是为了没有理由改变它。但无论值是否保留,它仍然是一个无用的指针,不是吗?

#4


2  

The signature of the global operator delete, as required by the standard 3.7.3.2/2:

根据标准3.7.3.2/2的要求,全局运算符的签名删除:

Each deallocation function shall return void and its first parameter shall be void*.

每个释放函数都应返回void,其第一个参数应为void *。

This means that delete cannot modify the pointer you pass to it, and it will always retain its value.

这意味着删除不能修改传递给它的指针,它将始终保留其值。

#5


1  

Consider, how would you check or rely on any "yes" or "no" answer? You can't. Or, you can, but the result of that checking (except for nullpointer) is Undefined Behavior.

考虑一下,您如何检查或依赖任何“是”或“否”的答案?你不能。或者,您可以,但检查的结果(nullpointer除外)是未定义的行为。

You can't check a non-null value after a delete, so the question is in general meaningless.

删除后无法检查非空值,因此问题通常无意义。

Also, the argument to delete can be an rvalue expression, so the question is meaningless.

此外,删除的参数可以是右值表达式,因此问题毫无意义。

Cheers & hth.,

干杯&hth。,

#6


1  

A pointer is not guaranteed to be of any meaningful value in of itself other than the range in which it was allocated and one past the end of that range.

除了分配指针的范围和超出该范围结束的指针之外,不保证指针本身具有任何有意义的值。

What you might be questioning is whether, say, you were doing your own leak checking so you wrote function to remove a pointer from a map after you had done a delete. That would use std::less which is guaranteed to work with pointers that do not point within a range, and would presumably work too with pointers that pointed to memory that is no longer valid.

您可能会质疑的是,您是否正在进行自己的泄漏检查,因此您在完成删除后编写了从地图中删除指针的功能。这将使用std :: less,它可以保证与指向范围内的指针一起使用,并且可能也会使用指向不再有效的内存的指针。

Of course you might get your garbage collecting to do the "remove" just before deleting the memory it was pointing to.

当然,在删除它指向的内存之前,你可能会收集垃圾进行“删除”。

As it is with the standard, if the value you pass to delete is not an l-value it is guaranteed to maintain the same value, but if it is an l-value it is implementation defined.

与标准一样,如果传递给delete的值不是l值,则保证保持相同的值,但如果它是l值,则它是实现定义的。

#7


1  

This question is important! I have seen that Visual Studio 2017 has changed pointer value after "delete". It coused a problem because I has using memory tracing tool. The tool was collecting pointers after each operator "new" and was checking them after "delete". Pseudo code:

这个问题很重要!我已经看到Visual Studio 2017在“删除”之后更改了指针值。它因为我使用了内存跟踪工具而引发了一个问题。该工具在每个操作符“new”之后收集指针,并在“删除”之后检查它们。伪代码:

Data* New(const size_t count)
{
    Data* const ptr(new Data[count]);
    #ifdef TEST_MODE
    DebugMemory.Collect(ptr);
    #endif
    return ptr;
}

void Delete(Data* const ptr)
{
    delete[] ptr;
    #ifdef TEST_MODE
    DebugMemory.Test(ptr);
    #endif
}

This code works good on Visual Studio 2008 but was failing on Visual Studio 2017 so I have changed the order of operations in second function.

此代码在Visual Studio 2008上运行良好但在Visual Studio 2017上失败,因此我更改了第二个函数中的操作顺序。

However The question is good and the problem exists. Experienced engineers should be aware of that.

但问题是好的,问题就存在了。有经验的工程师应该意识到这一点。