deleting an object twice?

R

Rick

Hi,

Does deleting an object more than one times incur undefined behavior? I
think it doesn't but just making sure... thanks

Rick
 
K

Karl Heinz Buchegger

Rick said:
Hi,

Does deleting an object more than one times incur undefined behavior?

The first delete renders the pointer to it invalid. Using an
invalid pointer invokes undefined behaviour.
I
think it doesn't but just making sure... thanks

You are wrong.
 
H

Hendrik Belitz

Rick said:
Hi,

Does deleting an object more than one times incur undefined behavior? I
think it doesn't but just making sure... thanks

Rick

It does. Delete renders a pointer to be invalid and so calling delete again
will result in undefined behaviour. To circumvent this, simply set the
pointer to NULL after deletion. Calling delete for a NULL pointer will do
nothing.
 
A

Ali R.

Rick said:
Hi,

Does deleting an object more than one times incur undefined behavior? I
think it doesn't but just making sure... thanks

Rick

Are you setting your pointer to null after the first delete? I think you
have deleting a null pointer mixed up with deleting a pointer twice. I am
not sure if this is a standard behavior or not but on the few compilers that
I have worked with delete checks for a null pointer and does nothing.
 
T

tom_usenet

Hi,

Does deleting an object more than one times incur undefined behavior? I
think it doesn't but just making sure... thanks

int* p = new int;
delete p;
delete p; //undefined behaviour

Generally double deletes cause heap corruption and, if you're lucky, a
crash. You can of course delete null pointers as often as you like.
e.g.

int* p = new int;
delete p;
p = 0;
delete p; //fine

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
 
A

Andrew Koenig

Does deleting an object more than one times incur undefined behavior? I
think it doesn't but just making sure... thanks

How can you possibly delete an object more than once? Once you have deleted
it, it no longer exists, so what are you deleting the second time?

If you are thinking of something like this:

int* p = new int;
delete p;
delete p;

then after the first "delete p", p is an invalid pointer -- the only thing
you can do with p is give it a new value.

So there is no question of deleting "an object" twice.
 
E

E. Robert Tisdale

Andrew said:
How can you possibly delete an object more than once?
Once you have deleted it, it no longer exists,
so what are you deleting the second time?

If you are thinking of something like this:

int* p = new int;
delete p;
delete p;

then after the first "delete p", p is an invalid pointer --

I object to your abuse of the English language.
The pointer p is *not* deleted.
The *object* to which pointer p points is deleted.
Pointer p is a valid pointer to an invalid object
(of type int in this case) because delete calls
the object's destructor to destroy the object.
the only thing you can do with p is give it a new value.

So there is no question of deleting "an object" twice.

The problem is that the second delete
is almost certainly a programming error -- a bug.
If you simply set the pointer p = NULL,
the bug will go undetected.
You can't do anything about this for built-in types
but you can for User Defined Types (UDTs):

class X {
private:
int Valid;
// other data members
public:
X(void) Valid(0x55555555) { }
~X(void) {
if (0x55555555 == Valid)
Valid == 0xaaaaaaaa;
else
std::cerr << "Invalid object of type X!" << std::endl;
}
// other public functions and operators
};
 
P

Peter van Merkerk

E. Robert Tisdale said:
I object to your abuse of the English language.
The pointer p is *not* deleted.

I don't think Andrew said so; he just said: "after the first "delete p"". He
didn't say that the pointer was deleted.
The *object* to which pointer p points is deleted.
Pointer p is a valid pointer to an invalid object
(of type int in this case) because delete calls
the object's destructor to destroy the object.


The problem is that the second delete
is almost certainly a programming error -- a bug.
If you simply set the pointer p = NULL,
the bug will go undetected.

It is not necessarilly a bug. There is a reason why you can do a delete on a
null pointer.
You can't do anything about this for built-in types
but you can for User Defined Types (UDTs):

class X {
private:
int Valid;
// other data members
public:
X(void) Valid(0x55555555) { }
~X(void) {
if (0x55555555 == Valid)
Valid == 0xaaaaaaaa;
else
std::cerr << "Invalid object of type X!" << std::endl;
}
// other public functions and operators
};

Even though this technique may work on some platforms with some compilers
under certain circumstances, it is not *guaranteed* to work. Once an object
has been deleted, the memory it occupied may have been overwritten, unmapped
(resulting in a page fault) or occupied by another object (possibly of the
same class). There is also a chance the vtable pointer of the deleted object
is damaged; if the pointer is used to call any virtual member function
(including the destructor) on the deleted object very weird things may
happen - good for hours of debugging fun.

Personnally I prefer resetting the pointer to NULL after deleting the object
it is pointing to. That way it easy to detect if the pointer is still
pointing to a valid object, and on most platforms leads to very predictable
behaviour when that pointer is accidentally dereferenced. Resetting the
pointer does not conflict with using a member variable to see if the object
is still valid. Even tough that technique is not 100% reliable, it increases
the chance that code that shouldn't work doesn't work (which is usually a
good thing). Member functions (not just the destructor) can use the member
variable with the magic number as a precondition. This technique can be
especially useful to detect lifetime issues i.c.w. having multiple pointers
to the same object.
 
D

David White

E. Robert Tisdale said:
I object to your abuse of the English language.
The pointer p is *not* deleted.

Who said it was?
The *object* to which pointer p points is deleted.

As far as I can see, neither the OP nor AK have stated or implied that it is
the pointer being deleted. Only the C++ source code says that :)
Pointer p is a valid pointer to an invalid object
(of type int in this case) because delete calls
the object's destructor to destroy the object.


The problem is that the second delete
is almost certainly a programming error -- a bug.
If you simply set the pointer p = NULL,
the bug will go undetected.

I'd say that would fix the bug rather than hide it, albeit unsatisfactorily.
And in some circumstances two deletes are quite normal. An object's member
pointer to a valid object might or might not have been deleted and assigned
to null before the destructor is reached, so you would like the destructor
to delete it regardless.

DW
 
A

Andrew Koenig

I object to your abuse of the English language.

That's your prerogative. Mine is to say that you're mistaken :)
The pointer p is *not* deleted.

I never said it was.
The *object* to which pointer p points is deleted.

Yes, that's what I said.
Pointer p is a valid pointer to an invalid object
(of type int in this case) because delete calls
the object's destructor to destroy the object.

Wrong. Once you have said "delete p", the value of p is now invalid. For
example, in

int* p = new int;
delete p;
int* q = p;

the attempt to copy p in order to initialize q yields undefined behavior, so
the implementation can do as it pleases.
The problem is that the second delete
is almost certainly a programming error -- a bug.

Yes, indeed -- I never said otherwise.
If you simply set the pointer p = NULL,
the bug will go undetected.

Yes indeed -- I never said otherwise.
You can't do anything about this for built-in types
but you can for User Defined Types (UDTs):

class X {
private:
int Valid;
// other data members
public:
X(void) Valid(0x55555555) { }
~X(void) {
if (0x55555555 == Valid)
Valid == 0xaaaaaaaa;
else
std::cerr << "Invalid object of type X!" << std::endl;
}
// other public functions and operators
};

And your point is what, exactly? Are you claiming that C++ requires some
particular behavior in the case of

X* p = new X;
delete p;
delete p;

It doesn't; the implementation can do as it pleases.
 
E

E. Robert Tisdale

Andrew said:
That's your prerogative. Mine is to say that you're mistaken :)


I never said it was.

I never said that you said that it was.
Ali R., Hendrik Belitz and tom_usenet said that it was.
Yes, that's what I said.


Wrong. Once you have said "delete p", the value of p is now invalid.
For example, in

int* p = new int;
delete p;
int* q = p;

the attempt to copy p in order to initialize q yields undefined behavior
so the implementation can do as it pleases.

Where is it written? (Please cite and quote the relevant document.)

Please compile and run the above code fragment on a platform
where the behavior is other than expected
and show us the diagnostic and/or incorrect result.
Yes, indeed -- I never said otherwise.

I never said that you said otherwise.
Yes indeed -- I never said otherwise.

I never said that you said otherwise.
And your point is what, exactly?
Are you claiming that
C++ requires some particular behavior in the case of

X* p = new X;
delete p;
delete p;

I made no such claim.
It doesn't; the implementation can do as it pleases.

I never said differently.

Please don't take my remarks personally. They are directed at
other subscribers reading this thread and *not* just you.
 
A

Andrew Koenig

I never said that you said that it was.

You said that I was abusing the English language. The only reason I could
imagine that you might make such a statement was that you thought I had said
something incorrect or unclear. So I went over each statement I made, in
order to point out why I think it is correct.
Where is it written? (Please cite and quote the relevant document.)

C++ standard, subclause 5.3.5, paragraph 4: "Note: The value of a pointer
that refers to deallocated storage is indeterminate."
Please compile and run the above code fragment on a platform
where the behavior is other than expected
and show us the diagnostic and/or incorrect result.

Attempting to use the value of an indeterminate pointer yields undefined
behavior, so an implementation is allowed to do as it plases with the
example above. Therefore, there is no such thing as unexpected behavior --
any behavior at all is permissible.
I never said that you said otherwise.

See above.
I never said that you said otherwise.

See above.
I made no such claim.


I never said differently.

Please don't take my remarks personally. They are directed at
other subscribers reading this thread and *not* just you.

Then why did you claim that I was abusing the English language?
 
J

Jumbo

E. Robert Tisdale said:
I never said that you said that it was.
Ali R., Hendrik Belitz and tom_usenet said that it was.

But you implied it when you said:
[quote snippet]
I object to your abuse of the English language.
The pointer p is *not* deleted.
[end quote]

What did you mean by this if you didn't mean what we think you mean?
 
R

Rolf Magnus

David said:
Who said it was?


As far as I can see, neither the OP nor AK have stated or implied that
it is the pointer being deleted. Only the C++ source code says that
:)


I'd say that would fix the bug rather than hide it, albeit
unsatisfactorily. And in some circumstances two deletes are quite
normal.

I see this as a design error. Each new should have exactly one delete,
certainly not less, but also not more. And IMHO, a good design will
prevent any intended double deletions. Setting the pointer to 0 after
delete might be a useful thing for release versions to prevent a crash
due to an overlooked double deletion. But while debugging, I want to
find those and thus don't want to set the pointer to 0. If at all, I'd
set it to something that enforces a crash.
An object's member pointer to a valid object might or might
not have been deleted and assigned to null before the destructor is
reached, so you would like the destructor to delete it regardless.

Then the ownership isn't clear. A dynamically allocated object should
have an owner that is responsible for deleting it.
 
D

David White

Rolf Magnus said:
I see this as a design error. Each new should have exactly one delete,
certainly not less, but also not more. And IMHO, a good design will
prevent any intended double deletions. Setting the pointer to 0 after
delete might be a useful thing for release versions to prevent a crash
due to an overlooked double deletion. But while debugging, I want to
find those and thus don't want to set the pointer to 0. If at all, I'd
set it to something that enforces a crash.

I don't see how you can always avoid double deletions. The logic of a class might dictate that
an object it created, and for which it has a member pointer, might or might not have been
deleted by the time the destructor is reached, or might not have been created at all. If it has
already been deleted, it might also have to be assigned to null because it might be used to
point to another new object later, e.g.,

class Device
{
BaseProtocol *m_pProt;
public:
Device() : m_pProt(0) {}
~Device() { delete m_pProt; }
bool Open(ProtocolType protType)
{
delete m_pProt;
switch(protType)
{ case TCP_IP:
m_pProt = new TcpIpProtocol; break;
case IPX_SPX:
m_pProt = new IpxSpxProtocol; break;
// more protocols
};
if(!m_pProt->Connect())
{ delete m_pProt; m_pProt = 0; return false;
}
return true;
}
// more members
};
Then the ownership isn't clear. A dynamically allocated object should
have an owner that is responsible for deleting it.

It's clear in the cases I was thinking of. The object that owns the pointer creates the object.

DW
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,150
Messages
2,570,853
Members
47,394
Latest member
Olekdev

Latest Threads

Top