Calling delete on variable allocated on the stack
No, it is not safe to call delete
on a stack-allocated variable. You should only call delete
on things created by new
.
- For each
malloc
orcalloc
, there should be exactly onefree
. - For each
new
there should be exactly onedelete
. - For each
new[]
there should be exactly onedelete[]
. - For each stack allocation, there should be no explicit freeing or deletion. The destructor is called automatically, where applicable.
In general, you cannot mix and match any of these, e.g. no free
-ing or delete[]
-ing a new
object. Doing so results in undefined behavior.
Deleting an object off the stack?
is it possible to explicitly delete an object that has been initialized on the stack?
No, it is not possible.
According to Paragraph 5.3.5/2 of the C++11 Standard on delete
expressions:
If the operand has a class type, the operand is converted to a pointer type by calling the above-mentioned
conversion function, and the converted operand is used in place of the original operand for the remainder of
this section. In the first alternative (delete object), the value of the operand of delete may be a null pointer
value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject (1.8)
representing a base class of such an object (Clause 10). If not, the behavior is undefined. [...]
Also relevant is Paragraph 3.7.3/3 about variables with automatic storage duration (i.e. allocated "on the stack"):
If a variable with automatic storage duration has initialization or a destructor with side effects, it shall not
be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to
be unused, except that a class object or its copy/move may be eliminated as specified in 12.8.
Is `delete ptr;` necessary in destructor even when memory is not dynamically allocated?
delete
operator can only be called on objects allocated with new
. If you haven't allocated new
memory, you cannot call delete
operator.
Take the following example:
int main() {
int a = 20;
int* ptr = &a;
delete ptr;
return 0;
}
If you compile this code, it surprisingly(??) compiles without warning.
However, the debugger breaks the code at the call to delete operator.
delete_scalar.cpp:
_CRT_SECURITYCRITICAL_ATTRIBUTE
void __CRTDECL operator delete(void* const block) noexcept {
#ifdef _DEBUG
_free_dbg(block, _UNKNOWN_BLOCK);
#else
free(block);
#endif
}
However, the following code works fine, as the memory has been allocated with new
:
int main() {
int* ptr = new int[5];
delete[] ptr;
return 0;
}
Calling delete on address of variable
Your original version does not assign i
to an address. It allocates a new int on the heap and initializes its value to 5, then copies that value into i
which is on the stack. The memory that you allocated (new
'ed) is inaccessible and gets leaked.
The reference version works because i
refers to the otherwise-anonymous new
'ed memory. Hence &i
gives the heap address. In your first version, &i
gives the address of the stack variable, not the heap memory, and deleting stack memory is bad news.
is deleting a variable allocated in heap using void pointer a bad thing?
Even though you are using an explicit type conversion, the rules for static_cast
apply. The relevant rule is in point 10 of the static_cast
page @ cppreference.com:
Conversion of any pointer to pointer to void and back to pointer to the original (or more cv-qualified) type preserves its original value.
In your case, you started with a pointer-to-int
. You converted that to pointer-to-void
when you initialized ptr
. You converted back to pointer-to-int
in the delete
statement. This preserves the original value, meaning that both (int *)ptr
and x
evaluate to the same address (and have the same type), hence
delete (int *)ptr;
and
delete x;
are equivalent. (I'd also add
delete static_cast<int*>(ptr);
to the list since getting in the habit of using static_cast
et al. instead of a C-style cast could save you headaches in the future.)
Related Topics
To_String Is Not a Member of Std, Says G++ (Mingw)
Concatenating Two Std::Vectors
Advantage of Switch Over If-Else Statement
C++ Lambda With Captures as a Function Pointer
When Should Std::Move Be Used on a Function Return Value
How to Print (Using Cout) a Number in Binary Form
How to Write Iso C++ Standard Conformant Custom New and Delete Operators
What's the Difference Between Assignment Operator and Copy Constructor
How to Determine If a String Is a Number With C++
Is #Pragma Once a Safe Include Guard
What Are Access Specifiers? Should I Inherit With Private, Protected or Public