Is it a very bad idea for a class to pass (*this) into a function? Strange bug...

Started by
14 comments, last by Sean_Seanston 9 years, 2 months ago
What is likely happening is that the BitmapFont is not copyable. That is, when you create a copy, and the copy goes out of scope, it destroys resources that the "original" is also using.

Something like this:

$ cat test.cpp
#include <iostream>
class Bad {
public:
    Bad() : pointer(new int(42)) {
        std::cout << "constructor: " << this << ", pointer: " << pointer << '\n';
    }

    ~Bad() {
        std::cout << "destructor: " << this << ", pointer: " << pointer << '\n';
        delete pointer;
    }

    int *pointer;
};

int main() {
    Bad original;
    Bad copy = original;
}
$ g++ test.cpp && ./a.out
constructor: 0x7fffeb5038a0, pointer: 0x131d010
destructor: 0x7fffeb5038b0, pointer: 0x131d010
destructor: 0x7fffeb5038a0, pointer: 0x131d010
*** Error in `./a.out': double free or corruption (fasttop): 0x000000000131d010 ***
Aborted (core dumped)
As you can see, there are two "this" pointer values, but only one "pointer" value. The destructor causes the pointer in "original" to also be invalidated.
Advertisement

What is likely happening is that the BitmapFont is not copyable. That is, when you create a copy, and the copy goes out of scope, it destroys resources that the "original" is also using.

Ahhh... of course, that makes sense. I should have noticed that possibility myself.

Now just checking the destructor... if I comment out the destructor of the underlying SpriteSheet object then it does stop happening. Yay.

Thanks for tracking that one down. Left me quite confused for some time.

Yes... I see what it ultimately leads to now; the GLuint variables referring to the texture and sampler get deleted when the texture wrapper class goes out of scope, and the VBOs of SpriteSheet do likewise.

As for a solution... I've been trying to think this through... and doing the ordinary deep copy of a pointer seems like it wouldn't be very straightforward. Am I right in thinking that to give a copy its own copy of the texture (and thereby allow it to release that texture on destruction), you'd have to go through loading the whole texture again, or is there another way in OpenGL?

Would it be better to work around it instead, and remember never to copy these classes like that? i.e. Just keep using my method of creating a new GameDateTime object with the same values as the current one. Sounds like bad practice to leave such a potential bug lying around, but the other way seems kind of elaborate and maybe wasteful to me.

The only other option I can foresee is giving it some way of knowing if a texture is in use, and only selectively deleting it if nothing else is using it. Not sure how practical that would be. Maybe it would work by incrementing some counter when the copy constructor is called, and then decrementing it on destruction? Feels kind of sloppy to me though and like it might be covering up bad design.

Or am I just tired and the solution is much simpler and more obvious than I realize? mellow.png

Sounds like this object should not own the texture at all, that should be owned by someone else instead. Someone who knows the actual lifetime of the texture.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

The solution is to understand the Rule of Three (this rule has recently grown a bunch of different names, but I think this still is the best name).

So, your BitmapFont class or potentially some of the other classes it uses, should be marked as "noncopyable". You can achieve that in C++11 by "deleting" the copy constructor and assignment operator, and in pre C++11 you can simulate this by declaring them private and not implementing them.

This will address the issue you mentioned of the silent bug lying around. Anywhere you are copying these objects should now give a compilation error (or possibly a link error).

The next thing to consider is the design. As Washu says, this design seems weak.


The solution is to understand the Rule of Three (this rule has recently grown a bunch of different names, but I think this still is the best name).

Rule of 0/3/5

Sounds like this object should not own the texture at all, that should be owned by someone else instead. Someone who knows the actual lifetime of the texture.

Hmmm... yes, that sounds about right.

So, your BitmapFont class or potentially some of the other classes it uses, should be marked as "noncopyable". You can achieve that in C++11 by "deleting" the copy constructor and assignment operator, and in pre C++11 you can simulate this by declaring them private and not implementing them.

This will address the issue you mentioned of the silent bug lying around. Anywhere you are copying these objects should now give a compilation error (or possibly a link error).

The next thing to consider is the design. As Washu says, this design seems weak.

Cool, sounds interesting.

I'll have a look and see what I can improve... thanks.

This topic is closed to new replies.

Advertisement