The following code
#include <iostream>
#include <map>
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
m.erase(i);
}
};
int main()
{
std::map<int, foo> m;
m.emplace(1, foo() );
std::cout << m.size() << std::endl;
m[1].kill(m, 1);
std::cout << m.size() << std::endl;
}
compiles without warning (g++), executes without error and judging by the output the kill
method erases the foo
object from the map. However, I feel that this might actually be undefined behavior. It seems that in the kill
method after the line m.erase(i)
this
no longer points to a valid object.
What does the C++ standard say about this?
When you enter your kill
, m[1]
(from m[1].kill(m, 1);
) statement has been fully evaluated as being the foo
object you are calling kill
on.
Then you do m.erase(i);
ending up destroying the current object foo
.
As far as you write absolutely no statement using the current object (this
) before you return from the kill
function, that's perfectly acceptable and safe (as commented by the posts referenced by Auriga and Barry). Even if the current object does not exist anymore, your function will return safely from the stack, no reason for it to fail as far as I know.
As an illustration, this would end up with undefined behaviour and must NOT BE DONE:
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
m.erase(i);
cout << attribute; // don't do that! current foo object does not exist anymore
}
int attribute;
};
So let's say what you are doing is risky, but valid and safe if you do it well.
As an illustration, this would end up with defined behaviour and CAN BE DONE:
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
int theAttribute = attribute;
m.erase(i);
cout << theAttribute; // OK!
}
int attribute;
};
Having a method delete the current object is probably not a good practice anyway (specially if another developer modifies the code later...he could easily make it crash with the first example above). At least put an explicit comment in the code to tell the current object could have been destroyed (note that kill
could destroy the current object, another one, or none...depending on m
content and i
):
struct foo
{
void kill(std::map<int, foo>& m, int i)
{
m.erase(i);
// careful! current object could have been destroyed by above statement and may not be valid anymore! Don't use it anymore!
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With