First of all emplace_back
constructs an object in place by forwarding its arguments. So what you end up doing is calling your class's copy constructor with the argument *this
.
I'm trying to think of a case where adding objects to a list inside the constructor is needed and I'm having a hard time. I think there are better alternatives.
Emplace it in the list from outside the constructor
Simply create it as follows.
myclassobjects.emplace_back(/*constructor params*/);
In C++17 this even returns a reference to the newly created object
MyClass& myclass_ref = myclassobjects.emplace_back(/*constructor params*/);
do_something_with_my_class_object(myclass_ref);
This is the cleanest and most efficient way to do it. It has the added benefit that you can create local objects without adding them to the list if needed.
Use a factory method that adds it to the list
If you absolutely must have every object in the list and you don't want it to be a copy, use a static factory method. If the list and the callee must share ownership, you can use a list of std::shared_ptr
s and do the following.
MyClass {
private:
MyClass(); // private constructor forbids on the stack variables
public:
static std::shared_ptr<MyClass> create_instance() {
auto ptr = make_shared<MyClass>(); // We can access the constructor here
myclass_objects.emplace_back(ptr);
return ptr;
}
}
On the other hand, if your list is guaranteed to outlive the callee's handler on the object, it is more appropriate to have a list of std::unique_ptr
s that hold the objects and return references to them.
MyClass {
private:
MyClass(); // private constructor forbids on the stack variables
public:
// pre C++17
static MyClass& create_instance() {
auto ptr = make_unique<MyClass>();
auto& ref = *ptr; // Store ref before we move pointer
myclass_objects.emplace_back(std::move(ptr));
return ref;
}
// C++17
static MyClass& create_instance() {
auto ptr = make_unique<MyClass>();
return *(myclass_objects.emplace_back(std::move(ptr)));
}
}
Of course, these examples only cover default constructors. Because you will usually need to work with more constructors, you will probably need a templated create_instance
that forwards its arguments to the constructor.