I'm trying intending to create a single instance of a type that gets shared among the items in a vector. Each of the vector's item types requires a pass-by-reference parameter in the constructor but I can't seem to get the vector to initialize properly.
//The type of each item in the vector
class PollingConfig_t
{
public:
PollingConfig_t(DebugPrinter_t& _debugPrinter) : _debugPrinter(debugPrinter) {}
private:
DebugPrinter_t& _debugPrinter; //Reference to the global instance of DebugPrinter_t
}
And for the actual globals:
DebugPrinter_t DebugPrinter(true); //One instance shared among vector items
std::vector<PollingConfig_t> PollingConfigs(4, PollingConfig_t(DebugPrinter)); //4 instances of PollingConfig_t, each with reference to DebugPrinter.
This doesn't compile and give me an error:
error: use of deleted function 'PollingConfig_t& PollingConfig_t::operator=(const PollingConfig_t&)'
HOWEVER, I can get it work seemingly as intended if I simply remove the ampersand in the _debugPrinter declaration.
private:
DebugPrinter_t _debugPrinter;
But wouldn't this create copies of the original instance DebugPrinter
for each of the vector's items? I mean if _debugPrinter
is declared as a DebugPrinter_t
instead of DebugPrinter_t&
it's no longer a reference, right?
std::vector
need to copy/move the elements in it (e.g when it is elarged and require reallocation).
In your case this is a problem because your element contains a reference which once initialized cannot be changed.
Adding operator=
is not a good solution because you will still have a problem assigning the reference.
And you are correct that having DebugPrinter_t _debugPrinter
is also not good because it will cause copies to be made.
You can solve it in various ways, e.g.:
Use a pointer instead of a reference:
class PollingConfig_t
{
public:
PollingConfig_t(DebugPrinter_t * pDebugPrinter) : m_pDebugPrinter(pDebugPrinter) {}
private:
DebugPrinter_t * m_pDebugPrinter; // pointer to the global instance of DebugPrinter_t
}
Then initialize the vector
with:
DebugPrinter_t DebugPrinter(true); //One instance shared among vector items
std::vector<PollingConfig_t> PollingConfigs(4, PollingConfig_t(&DebugPrinter)); // NOTE the & to take the address of the global object to initialize the pointer
And in order to use the global object from within PollingConfig_t
, use: m_pDebugPrinter-> ...
.
Use a std::shared_ptr
:
The std::shared_ptr
support multile owners, and also takes care of the lifetime of the object.
class PollingConfig_t
{
public:
PollingConfig_t(std::shared_ptr<DebugPrinter_t> pDebugPrinter) : m_pDebugPrinter(pDebugPrinter) {}
private:
std::shared_ptr<DebugPrinter_t> m_pDebugPrinter; // shared_ptr to the global instance of DebugPrinter_t
}
You need to change the creation of the global object and the vector as following (note the usage of std::make_shared
for creating the global object):
std::shared_ptr<DebugPrinter_t> DebugPrinter = std::make_shared<DebugPrinter_t>(true); //One instance shared among vector items
std::vector<PollingConfig_t> PollingConfigs(4, PollingConfig_t(DebugPrinter)); // NOTE the shared_ptr is passed by value. It keeps a reference count on the object.
Using the global object from within PollingConfig_t
is the same as with a raw pointer: m_pDebugPrinter-> ...
.
Use a singleton for the DebugPrinter_t
object:
Since you have only one instance shared by all entities, you can use the signleton design pattern.
This way you don't even need to add a member to each PollingConfig_t
because all element will have access to the singleton.
I mentioned this the last since it is somewhat discouraged.
But since you have a global object anyway (which is the common claim against singletons) it might fit.