Hello again.
Taking into consideration all that has been said in this thread I have been improving my design through several iterations, trying out different paradigms like the pimpl idiom etc.
I really liked the encapsulation that the pimpl idiom provided, but I had problems with how the code was structured and I did not find it very intuitive.
The style I have decided to use is a kind of opaque pointer that works just like the pimpl idiom, except that instead of having a "hidden" implementation class, there is instead a "hidden" accessor class that is a friend of the opaque pointer. This makes the code much easier to read (for me) and the usage fits very well with the SDL interface, which is what I am using for windowing, events etc.
I also moved away from using namespaces to group functionality, as function signatures are (or should be) clear enough to show how they should be used
This is how I implemented it: (psuedocode)
Test.h
class TextureManager
{
friend class TextureManagerAccessor;
TextureManager()
{
_textures.reserve(1000);
}
~TextureManager()
{
for (auto& kvp : _textures)
{
if (kvp.second == nullptr)
{
continue;
}
delete kvp.second;
kvp.second = nullptr;
}
}
std::unordered_map<unsigned int, SDL_Texture*> _textures;
};
TextureManager* CreateTextureManager();
DestroyTextureManager(TextureManager*);
DoSomethingFunny(TextureManager*);
Test.cpp
class TextureManagerAccessor
{
public:
static TextureManager* Create();
static void Destroy(TextureManager*);
};
TextureManager* TextureManagerAccessor::Create()
{
return new TextureManager();
}
void TextureManagerAccessor::Destroy(TextureManager* textureManager)
{
delete textureManager;
textureManager = nullptr;
}
TextureManager* CreateTextureManager()
{
return TextureManagerAccessor::Create();
}
DestroyTextureManager(TextureManager* textureManager)
{
if (textureManager == nullptr)
{
return;
}
TextureManagerAccessor::Destroy(textureManager);
}
DoSomethingFunny(TextureManager* textureManager)
{
// something funny
}
Main.cpp (usage)
int main()
{
auto textureManager = CreateTextureManager();
DoSomethingFunny(textureManager);
DestroyTextureManager(textureManager);
return 0;
}
I am very happy with how this turned out.
I realize some people are against using a friend class in this manner, but I do not see any problem with it, as I consider the instance, the accessor and the related free functions as one "unit".
Thanks for all your help. =)