Reputation: 65
Basically i have a one struct that contains objects to share between classes as following;
struct CoreComponents
{
std::unique_ptr<a> m_A = std::make_unique<a>();
std::unique_ptr<b> m_B;
std::unique_ptr<c> m_C = std::make_unique<c>();
};
And in my main class i own it via unique_ptr;
class Game
{
...
private:
std::unique_ptr<CoreComponents> m_Components;
...
};
Then i have other n classes which i need to access that m_Components object from it's functions without creating copies. (i will not modify contents of that object)
I tried using shared_ptr to hold m_Components in Game class then pass it to other classes (to their constructors) via value and store it but that scenario causes memory leaks. (i use memcheck for checking leaks) I found out that it's the cause of the leak but i couldn't figure out why exactly.
Shared_ptr scenario
Constructor of class which i need to access CoreComponents object;
GameScene::GameScene(std::shared_ptr<CoreComponents> components)
: m_Components(std::move(components))
I'm trying to hold it as member of GameScene class then use it in functions;
std::shared_ptr<CoreComponents> m_Components;
And this is how i pass it from inside of the Game class;
auto gs = std::make_unique<GameScene>(m_Components)
General usage inside GameScene class;
m_Components->m_A->draw(*m_OtherObjectInsideGameScene);
So what is the best way to create similar design using modern c++? I was trying to avoid Singleton pattern but do i have to use it to achieve this or it's possible with better smart pointer usage?
PS: CoreComponents struct needs to be deleted from memory when Game class is destroyed.
Upvotes: 1
Views: 528
Reputation: 41509
It seems that you correctly separate the concerns of ownership and usage. The only trouble you have is how to forward the components to the rest of your system.
I would keep your owning structure, and create dedicated structures for the specific users:
struct CoreComponents {
unique_ptr<A> a; unique_ptr<B> b; ...
};
struct PartOfTheSystem {
void use(A& a, B& b);
};
struct Game {
CoreComponents components;
PartOfTheSystem user;
void stuff() {
user.use(*components.a, *components.b);
}
};
Yes: more typing.
But also: very clear logic: construction/ownership and use are separate concerns, and this is perfectly clear by design! Also refer to https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rr-smartptrparam.
Upvotes: 1
Reputation: 385174
The best way if you have shared objects is indeed to use a shared_ptr
.
A unique_ptr
is for unique ownership.
If you had memory leaks, it's time to investigate why that was, and fix them! Your report suggests a cyclical reference. Check for accidental lambda capture, and in some places you perhaps meant to use weak_ptr
instead.
Using a singleton for this is like fixing your car's broken tyre by setting the whole thing on fire and taking a donkey instead. Your unique_ptr
approach is more like fixing your car's broken tyre by removing it and driving on rims for the lols.
Upvotes: 1