Lapin
Lapin

Reputation: 119

How come new object's members are not uninitialized with std::make_unique?

Despite the default values of X, Y and Z in Position, when it is initialized in create() none of these variables seem to have been initialized at all. I can set them and then retrieve them, but the default value is never seen. I've tried initializing them various ways but with no success.

How do I use std::make_unique to return a unique_ptr of type T with its default values set?

#include <iostream>
#include <unordered_map>
#include <memory>
#include <typeindex>

class Component
{

public:
    Component() {};
    virtual ~Component() {};
};

class Position : public Component
{
public:
    Position(){};
    float x = 123;
    float y = 321;
    float z = 666;
};

std::unordered_map<std::type_index, std::unordered_map<uint32_t, std::unique_ptr<Component>>> components;

template<typename T>
T& get(uint32_t id)
{
    return reinterpret_cast<T&>(components[std::type_index(typeid(T))].at(id));
}

template<typename T>
void create(uint32_t id)
{
    components[std::type_index(typeid(T))].emplace(id, std::make_unique<T>());
}

int main()
{

    create<Position>(8);
    std::cout << get<Position>(8).z << std::endl; //Value not initialized
    get<Position>(8).z;
    std::cout << get<Position>(8).z << std::endl; //Still not
    get<Position>(8) = Position();
    std::cout << get<Position>(8).z << std::endl; //Now works, but unwanted creation of temporary Position
    get<Position>(8).z = 42;
    std::cout << get<Position>(8).z << std::endl; //Works
    //New try
    create<Position>(8);
    return 0;
}

Upvotes: 0

Views: 224

Answers (1)

cplusplusrat
cplusplusrat

Reputation: 1445

The problem is in your get method. Change it as below and it should resolve the issue.

return reinterpret_cast<T&>(*(components[std::type_index(typeid(T))].at(id)));

Your components[std::type_index(typeid(T))] returns another map and the .at() returns a std::unique_ptr. You were originally casting the unique_ptr using reinterpret_cast which resulted in undefined behavior.

While we are on the subject, do not use reinterpret_cast for casting across hierarchies. Use dynamic_cast. The dynamic_cast has a well defined behavior when the casting fails for both references and pointers.

In short, you were doing a reinterpret_cast<Position&>(uniquePtrToPosition) which is illegal C++.

Upvotes: 4

Related Questions