'Create unique pointer with make_unique and move?
I have an Entity class with a private constructor and public CreateEntity function. CreateEntity stack-allocates new entities. In my app, I'd like to use a unique pointer to the returned entity. I found a solution with a temporary unique pointer and two move instructions. How do I write the two lines in Start() with make_unique and a single move instruction?
class Entity
{
public:
Entity(const Entity&) = delete;
Entity& operator=(const Entity&) = delete;
Entity(Entity&&) = default;
Entity& operator=(Entity&&) = default;
static Entity CreateEntity();
private:
Entity(id_t id): m_ID(id) {}
private:
uint32_t m_ID;
};
Entity Entity::CreateEntity()
{
static id_t currentID = 0;
return Entity{currentID++};
}
struct Lucre : public Application
{
bool Start();
std::unique_ptr<Entity> m_Object;
}
bool Lucre::Start()
{
std::unique_ptr<Entity> ptr( new Entity(std::move(Entity::CreateEntity())));
m_Object = std::move(ptr);
}
Solution 1:[1]
You can combine the 2 lines in Lucre::Start() like this:
m_CameraObject.reset( new Entity( Entity::CreateEntity() ) );
Here, the return of Entity::CreateEntity() is moved, but no std::move() is needed as the return is already prvalue.
Solution 2:[2]
Just replicating the behavior of the shown lines:
m_CameraObject = std::make_unique<Entity>(Entity::CreateEntity());
This will perform a single move construction of Entity and a single move assignment of std::unique_ptr (assuming m_CameraObject is of type std::unqiue_ptr<Entity>) in addition to the non-move/copy object constructions for Entity and std::unqiue_ptr (guaranteed in C++17 or later, otherwise likely).
The std::move are not required in this, since both Entity::CreateEntity() and std::make_unique<Entity>(Entity::CreateEntity()) are already prvalues. In your original the std::move around Entity::CreateEntity() is also redundant.
However it is difficult to tell without full code whether this is what you really want to do. It may be that letting the factory function return a std::unique_ptr<Entity> directly is the better option. Then a move constructor call for Entity wouldn't be required.
Solution 3:[3]
I may not have understood your needs correctly, but the sample code below:
- Also implements an
Entityobject in such a way that every instance has a different ID. - Still hides the
Entityclass implementation details. Before, you were creating anEntityobject withauto e = Entity::CreateInstance();. Now, you can do the same withauto e = Entity{};. That is, user knows nothing about IDs in both cases. - Simplifies the creation of heap instances of
Entityby adding a default constructor toEntity. Now, you can just initialize yourLucre::m_Objectmember withm_Object{ std::make_unique<Entity>() }.
#include <cstdint> // uint32_t
#include <iostream> // cout
#include <memory> // make_unique, unique_ptr
class Entity
{
public:
Entity(): m_ID{currentID++} {}
Entity(const Entity&) = delete;
Entity& operator=(const Entity&) = delete;
Entity(Entity&&) = default;
Entity& operator=(Entity&&) = default;
auto getID() const { return m_ID; }
friend std::ostream& operator<<(std::ostream& os, const Entity& e) { return os << e.m_ID; }
private:
static inline uint32_t currentID;
uint32_t m_ID;
};
struct Lucre
{
Lucre() : m_Object{ std::make_unique<Entity>() } {}
friend std::ostream& operator<<(std::ostream& os, const Lucre& l) { return os << l.m_Object->getID(); }
private:
std::unique_ptr<Entity> m_Object{};
};
int main()
{
Lucre lucre1{};
Lucre lucre2{};
std::cout << "lucre1 = " << lucre1 << ", lucre2 = " << lucre2 << "\n";
}
// Outputs:
//
// lucre1 = 0, lucre2 = 1
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | rturrado |
