I'm using OpenGL (C API) and encapsulating a few things in classes. Basically calls to glGenX
generate GLuint
s that are handles to the actual thing created. When you're cleaning up you should call glDeleteX
on these handles.
What this means, is that for me to have a class that holds these (as well as encapsulates some other stuff specific to them) and be able to copy instances and pass them around, the class needs internal reference counting so that it only calls glDeleteX
when there's no more references.
I've done this twice now and I'm looking at it for a third class. I can see quite a few classes I'm making need this; so I want to use templates to make it easier.
Here's an example of the original class with the reference counting to only call glDeleteX
at the appropriate time:
class Texture
{
public:
Texture(const GLuint texture) : m_data(new Data(texture)) {}
Texture(const Texture& t) : m_data(t.m_data) { ++m_data->m_count; }
Texture(Texture&& t) : m_data(t.m_data) { ++m_data->m_count; }
~Texture() { if(--m_data->m_count == 0) delete m_data; }
void Bind(GLenum target, GLint location) const { /* do some stuff */;
void Release() const { /* do some stuff */
GLuint GetTexture() const { return m_data->m_texture; }
private:
class Data
{
public:
Data(const GLuint texture) : m_count(1), m_texture(texture) {}
Data(const Data& data) : m_count(1), m_texture(data.m_texture) {}
~Data() { glDeleteTexture(1,&m_texture); }
GLuint m_texture;
unsigned int m_count;
};
Data* m_data;
};
Here's my attempt at templatizerating it:
template<typename... Ts>
class ReferenceCountedObject
{
public:
ReferenceCountedObject(const Ts... args)
:
m_data(new Data(args...))
{}
ReferenceCountedObject(const ReferenceCountedObject& h)
:
m_data(h.m_data)
{
++m_data->m_count;
}
ReferenceCountedObject(ReferenceCountedObject&& h)
:
m_data(h.m_data)
{
++m_data->m_count;
}
virtual ~ReferenceCountedObject()
{
if(--m_data->m_count == 0)
delete m_data;
}
protected:
class Data
{
public:
Data(const Ts... args)
:
m_count(1),
m_dataMembers(args...)
{
}
Data(const Data& data)
:
m_count(1),
m_dataMembers(data.m_dataMembers)
{
}
virtual ~Data()
{
std::cout << "deleting base" << std::cout;
}
std::tuple<Ts...> m_dataMembers;
unsigned int m_count;
};
Data* m_data;
};
The idea is that the internal Data
class might need just one GLuint
handle for class Texture
but it might need three different ones for another type. So, that's why there's the internal tuple
.
Now, the problem I have. Here's my original class now deriving from this templatized class:
class Texture : public ReferenceCountedObject<GLuint>
{
public:
Texture(GLuint texture) : ReferenceCountedObject(texture) {}
Texture(const Texture& t) : ReferenceCountedObject(t) {}
Texture(Texture&& t) : ReferenceCountedObject(t) {}
void Bind(GLenum target, GLint location) const { /* does that stuff */}
void Release() const { /* does that stuff */ }
GLuint GetTexture() const { return std::get<0>(m_data->m_dataMembers); }
protected:
};
How can I define the destructor of the base classes Data
? So far, I've tried doing this:
Change the base class a bit:
template<class DataType, typename... Ts>
class ReferenceCountedObject
{
/* ... */
protected:
DataType* m_data;
};
So this way you can provide the DataType and just override the virtual destructor:
class Texture : public ReferenceCountedObject<Texture::TData,GLuint>
{
/* ... */
protected:
class TData : public ReferenceCountedObject::Data
{
public:
~TData()
{
std::cout << "deleting derived" << std::cout;
glDeleteTextures(1,&std::get<0>(m_dataMembers));
};
};
}
But I can't instantiate ReferenceCountedObject
with Texture::TData
because TData
is a part of what i'm trying to define.
How can I do this correctly? I concede that I could be going about this in a completely incorrect way.
Aucun commentaire:
Enregistrer un commentaire