Deep copy of a SDL_Texture*

Hi,

I have a class that contains SDL_Texture* m_texture as member variable. This means to avoid memory leaks I have to write a custom Destructor that calls SDL_DestroyTexture(m_texture), right?

Because I have a varying number of instances of this class i wanted to handle them with a std::list. See the following example:

Code:
list mylist;

//…

if (condition){
myclass newinstance;
newinstance.Init();
mylist.push_back(newinstance);
}

//…

for (list::iterator i = mylist.begin(); i != mylist.end(); ++i){
i->foo();
}

In myclass::Init() the SDL_Texture* is created via SDL_CreateTextureFromSurface(). The problem now is, that std::list::push_back() makes a copy of newinstance and attaches it to mylist. This means, the pointer to m_texture only gets shallow copied. By the end of the if-clause the Destructor of the original newinstance gets called and destroys the SDL_Texture its SDL_Texture*-pointer points at. The problem now is, that the pointer of the newinstance in mylist points at the very same SDL_Texture that is now destroyed.

Normally this wouldn’t be much of a problem; just write your own copy-constructor (and operator=) that make a deep copy of the pointer. Not so with SDL_Textures* as it seems like I can’t do anything with them. When trying the standard ay of deep copying:

Code:

myclass::myclass(const myclass &other){
m_texture = new SDL_Texture(*other.m_texture);
}

compilation fails with the Error “SDL_Texture doesn’t have a constructor”. Does this mean, I can’t deep copy a SDL_Texture* at all? Is what I’m doing conceptually bad?

Currently I’m running this with a workaround by generating a completely new SDL_Texture* in the copy-constructor like I would in the Init(). But this looks like a very poor solution. Is there a better way?

if your class does not create the texture itself, it should not destroy it in its destructor and its copy constructor should merely use the same copy of the texture as the original instance. If your class does create the SDL texture, it may be wise to pass around a shared_ptr:

Code:

class TexturePtr
{
public:
TexturePtr(SDL_Texture *texture)
{
m_texture = texture;
m_count = new unsigned int(1);
}
TexturePtr(const TexturePtr& other)
{
m_texture = other.m_texture;
m_count = other.m_count;
(*m_count)++;
}
~TexturePtr()
{
(*m_count)–;
if((*m_count) == 0)
{
SDL_DestroyTexture(m_texture);
delete m_count;
}
}
SDL_Texture *Get(){ return m_texture; }
protected:
SDL_Texture *m_texture;
unsigned int *m_count;
};------------------------
Nate Fries

I think there’s no way to do the deep copy on textures, as it would resides on the GPU’s memory. Besides it would be very ineffecient and expensive to do. Bsides you need only one copy of texture to render it on screen, the rest of them would be just a waste on the memory.

What you could do is to add reference counting. Uppon creatiion, assign the count to 1. On every copy constructor and assignment calls, add the count by one. On every destructor, minus the count by one. Free the texture only when the reference count is 0. This is basically what Nathaniel J Fries do in the code in his reply. Also using smart pointer like std::shared_ptr (he also pointed out already) manages reference counting for you. Be aware, though shared_ptr uses delete expression to free resource if you don’t supply the custom deleter function.

Or, you could even prevent copying by using list<myclass*> instead of list, just don’t forget clean up the resource other wise results in memory leaks. list<std::shared_ptr> also works.

Thank you both, that really was helpful.