I am trying to write a class whose objects are aware of each other (i.e. have a pointer to all the objects). I can't understand some aspects of implementation of this idea regarding smart pointers and static members.
The class can be thought of as a game object that needs to be able to access member functions and properties of other game objects.
To my best knowledge, the common way to implement the desired design is static vector which would contain the pointers to other objects. If operating by raw pointers, the task is not very complicated:
GameObject.h:
#pragma once
#include <vector>
class GameObject
{
private:
static std::vector< GameObject* > objects;
public:
GameObject()
{
objects.push_back(this);
}
};
GameObject.cpp:
#include "GameObject.h"
std::vector< GameObject* > GameObject::objects = {};
This would actually give what I need. But if I want to use smart pointers, things are not as straightforward to me. From this question and from the 'Effective Modern C++' book by Meyers I found out about std::enable_shared_from_this
and shared_from_this()
. But, additionally, the reference clearly states that shared_from_this()
is allowed to be used only in case the object already owned by a std::shared_ptr<>
.
So it is impossible to simply push into the static vector this
pointers (or std::shared_ptr
constructed over it) in the constructor in the same manner as previously. The minimum set of code allowing the design which I found out is the following:
GameObject.h:
#pragma once
#include <vector>
#include <memory>
class GameObject : public std::enable_shared_from_this<GameObject>
{
private:
static std::vector< std::shared_ptr<GameObject> > objects;
public:
GameObject() {}
void emplace_ptr()
{
objects.emplace_back(shared_from_this());
}
};
GameObject.cpp:
#include "GameObject.h"
std::vector< std::shared_ptr<GameObject> > GameObject::objects = {};
main.cpp:
#include "GameObject.h"
int main(int argc, char* argv[])
{
std::shared_ptr<GameObject> game_object{ new GameObject{} };
game_object->emplace_ptr();
return 0;
}
So I am apparently obliged to create a pointer to the object somewhere outside and then explicitly call a method to push the pointer to the static vector (as I am not allowed to do this in constructor).
I am getting the impression that the required code is getting unnecessarily complex (comparing the raw pointer case) or I am doing something nonsensical.
- Does my strive for making object aware of each other make sense at all? Is it a common problem or some other approach is usually taken?
- Are static vectors a sound solution to the problem?
- How to construct such vectors using smart pointers, but, preferably,
with no intervention from the outside and with no need to create the
special function
emplace_ptr()
for the purpose?