0
template <typename StoredT>
class InternalObject {
public:
    using RefCountT = unsigned short;

    template <typename... CtorTs>
    static void* emplace(CtorTs&&...);

    Types type;
    RefCountT reference_count;
    bool is_immovable;
    StoredT stored_value;
    
    InternalObject();
    InternalObject(StoredT);
    ~InternalObject();
};

My class has a member StoredT stored_value which I would like to be able to construct using emplace and return a void* to it.

However, if I want to do this, I would have to do InternalObject<StoredT> *io_ptr = new InternalObject<StoredT>; which would force me to default-construct stored_value.

The solution I attempted was to allocate the appropriate amount of space as an array of unsigned char (the returned pointer is a heap pointer). Then, I tried to increment the pointer by appropriate amounts and modify the value there.

A more reproducible & complete example which does not produce a valid (non-POD) value for two.

#include <iostream>
#include <vector>

struct S {
    int one;
    std::vector<int> two;
};

int main() {
    unsigned char *s_ptr = new unsigned char[sizeof(S)];
    S *s = reinterpret_cast<S*>(s_ptr);
    
    *s_ptr = 100; // Fine

    std::vector<int> *vec_ptr = reinterpret_cast<std::vector<int>*>(s_ptr + sizeof(int));
    *vec_ptr = {5,6,7};
    
    std::cout << s->two.capacity() << "\n"; // big ol' number

    return 0;
}
Doot
  • 555
  • 5
  • 15
  • 2
    You can leverage a `std::vector`. You can have a `std::vector stored_value` and then use `vector`'s `emplace` function to add the object into it so there is no default construction. – NathanOliver Jan 29 '21 at 13:50
  • 2
    `std::vector` would be a good choice if multiple objects needed deferred construction (or if you can't use C++17), but `std::optional` is a better choice in this scenario since it avoids dynamic allocation for the `StoredT`. – johnmastroberti Jan 29 '21 at 13:56

1 Answers1

3

Consider using std::optional<StoredT>, which will allow you to defer the construction of the StoredT that you want to hold:

#include <optional>
template <typename StoredT>
class InternalObject {
public:
    using RefCountT = unsigned short;

    template <typename... CtorTs>
    void emplace(CtorTs&&... args) {
        stored_value.emplace(args...);
    }

    Types type;
    RefCountT reference_count;
    bool is_immovable;
    std::optional<StoredT> stored_value;
    
    InternalObject();
    InternalObject(StoredT);
    ~InternalObject();
};
johnmastroberti
  • 847
  • 2
  • 12