I have a question about returning a local pointer,
does the folloing code violates the local pointer rule ?
I found similar quetion, but the vector doesn't pop in that case,
so.. if the vector pop back, will it still valid in this case?
suppose, v contains v.push_back (new card())
class C {
std::vector<card> v;
public:
card* lastCard() {
// point to the last element of v
card* tmp = &v.back();
// the last element of v is destroyed, the memory is still reachable, but the object will have been destroyed.
v.pop_back();
// return the pointer to where the object used to be, obviously you're no longer pointing to an
// object and it's an error to use the pointer
return tmp;
};
Version 2, use the reference.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class C {
std::vector<card> v;
public:
card* lastCard() {
// refer to the last element of v
card& tmp = v.back();
// the last element of v is destroyed, the memory is still reachable, but the object will
// have been destroyed.
v.pop_back();
// we refer to an object that is gone, we can still get the address of where we refer to,
// but there's no object there anymore, and it's an error to try to use such an object
return &tmp;
};
Version 3, use a value
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class C {
std::vector<card> v;
public:
card* lastCard() {
// take a copy of the last element of v
card tmp = v.back();
// the last element of v is destroyed, but we have have a copy, we're ok so far
v.pop_back();
// Now we have a problem. We're returning the address of an object that will be destroyed,
// and the memory will be reused immediately, as the address is on the stack.
return &tmp;
};
So, what's really wrong? It's a matter of design. It's probably incorrect for an object to have a method called lastCard() that deletes the last card. You'd expect it to just return the last entry. So a more appropriate version might be:
1 2 3 4 5 6 7 8 9 10
class C {
std::vector<card> v;
public:
const card& lastCard() const {
return v.back();
}
void removeLastCard() {
v.pop_back();
}
};
Actually I wouldn't return a reference (unless you absolutely have to). If you return a reference and call removeLastCard() at the wrong time (before you are finished with the object) it is invalidated and it really hard to figure out why. So:
1 2 3 4 5 6 7 8 9 10
class C {
std::vector<card> v;
public:
card lastCard() const { // This way it is not a proble to call removeLastCard() at any time
return v.back();
}
void removeLastCard() {
v.pop_back();
}
};