0

How can I use this as a persistent pointer, so it would work outside of the current scope?

As for this example, I don't know how should I set the fx.parent:

class Effect
{
    Card* parent;
};

class Card
{
    vector<Effect> effects;
    void addEffect(Effect);
};

Card::addEffect(Effect fx)
{
    /*
     * the `this` pointer is not persistent and
     * will not work outside of this scope
     */
    fx.parent = this; 
    this->effects.push_back(fx);
}

PS: I'd be grateful for any literature about when pointers get destroyed, invalidated, etc. I could not really find anything readable. Nothing at all, actually.

Mikulas Dite
  • 7,790
  • 9
  • 59
  • 99

4 Answers4

2

The this pointer of an object is the same as taking the address:

#inclide <iostream>

class X{
public:
    X* GetThis(){
        return this;
    }
};

int main(){
    X x;
    X* addr_x = &x;
    X* this_x = x.GetThis();
    if(addr_x == this_x)
        std::cout << "Both are the same" << std::endl;
    else
        std::cout << "Shouldn't happen" << std::endl;
}

See at Ideone. As such, this is just a normal pointer to your class with a special name, so there's no problem with your code regarding the use of this. Aside from that, there are some errors though, like the missing return type in the definition of Card::addEffect and Card* parent in class Effect being private and as such it cannot be accessed by Card.

Xeo
  • 129,499
  • 52
  • 291
  • 397
2

Pushing elements into containers copies them. So you should link the copy, not the original:

Card::addEffect(Effect fx)
{
    effects.push_back(fx);
    effects.back().parent = this;
}

Otherwise, you will link to a local variable that goes out of scope when addEffect returns.

Note that this code generates another copy because of pass-by-value. Let's get rid of that:

Card::addEffect(Effect const& fx)
{
    effects.push_back(fx);
    effects.back().parent = this;
}

Also note that as soon as the capacity is exhausted, the vector will do an internal reallocation, and all pointers will become invalid. The easiest workaround is to reserve enough space from the beginning:

Card::Card()
{
    effects.reserve(1000);   // never more than 1000 effects at once
}

If that is unacceptable to you, you must either use a different container (std::list<Effect>) or put your effects on the heap and manage them manually (std::vector<Effect*>) or with a smart pointer (std::vector<boost::shared_ptr<Effect> >).

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Why is that? I mean, of course that `push_back` copies, but why does not the copied object have the very same pointer set? Shouldn't the copy contain everything the original object does? (in the first level at least for a shallow copy) – Mikulas Dite Mar 20 '11 at 14:14
  • 1
    @Mik: It's not the contents that matter, but the identity. – fredoverflow Mar 20 '11 at 14:15
  • Thanks, this exhaustive answer is extraordinary valuable to me. – Mikulas Dite Mar 20 '11 at 14:20
  • Shouldn't every copy of an `Effect` make a shallow copy of `Card* parent` and therefore shouldn't the copies not matter? – Xeo Mar 20 '11 at 14:21
  • @Xeo: You are right, of course. I somehow assumed that the problem had to do with pointers to effects :( – fredoverflow Mar 20 '11 at 14:24
  • @FredOverflow Now that I am reading this again, I have an urgent temptation to point out that I was not being sarcastic. I meant that I am actually thankful for the whole answer above. Hope I made it clear now : ) – Mikulas Dite Mar 20 '11 at 15:30
0

Ok, so it goes like this:

First of all the keyword "this" means the current object.
So in this context:

Card::addEffect(Effect fx)
{
    fx.parent = this; 
    this->effects.push_back(fx);
}

this is the Card object in which the addEffect() function was called..

Second, pointers don't get invalidated or destroyed. You can destroy the object they are pointing at by using the delete operator:

Blah* pointer = new Blah();
delete pointer;
Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
  • I know that `this` is a pointer to the `Card` object. That is why I used it as a parent in the first place. Thanks for pointing out that the pointer is never invalidated, I suppose I must have made an error somewhere else. – Mikulas Dite Mar 20 '11 at 14:10
  • 1
    `delete` doesn't "destroy a pointer". It destroys *what the pointer points to*. The pointer itself is "destroyed" (a no-op) when it goes out of scope. – Fred Foo Mar 20 '11 at 14:10
0

The way you keep track of your card object can also cause problems. When a copy is made of your card object the parent pointers will keep pointing to the original Card object. You will need to write a copy constructor to solve this issue or prevent copying from happening.

Eelke
  • 20,897
  • 4
  • 50
  • 76