Home > Back-end >  "Nested" make_unique calls failing on std::uninitialized_copy()
"Nested" make_unique calls failing on std::uninitialized_copy()

Time:01-24

New to C and mostly enjoying the learning curve, but struggling to solve this one.

I'm needing to satisfy this requirement in two different related places

std::unique_ptr [is typically used] as the element type in move-aware containers, such as std::vector, which hold pointers to dynamically-allocated objects (e.g. if polymorphic behavior is desired)

Compilable code (toggle the "working" and "not working" to cause build/fail):

#include<vector>
#include<memory>

class Entity;

class Action
{
    public:
        Action() = default;
};

class World {
    std::vector<std::unique_ptr<Entity> > entities;
    public:
        World();
};

class Entity {
    public:
        Entity() = default;
};

class Animal: public Entity {
    protected:
        // Not working - log below
        std::vector<std::unique_ptr<Action> > actions;
        // Working fine but doesn't support polymorphic behaviour
        //std::vector<Action> actions;
    public:
        Animal() = default;
};

class Person: public Animal
{
    protected:
        World& world;
    public: 
        Person(World& world);
};

Person::Person(World& world) : world(world)
{
}

World::World()
{
    Person first = Person(*this);
    entities.push_back(std::make_unique<Person>(first));
}

Which barfs the error:

/usr/include/c  /9/bits/stl_uninitialized.h|307 col 37 error| required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<Action>*, std::vector<std::unique_ptr<Action> > >; _ForwardIterator = std::unique_ptr<Action>*; _Tp = std::unique_ptr<Action>]’
/usr/include/c  /9/bits/stl_vector.h|555 col 31 error| required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<Action>; _Alloc = std::allocator<std::unique_ptr<Action> >]’
test.cpp|23 col 7 error| required from ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = Person; _Args = {Person&}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<Person, std::default_delete<Person> >]’
test.cpp|48 col 54 error| required from here
/usr/include/c  /9/bits/stl_uninitialized.h|127 col 72 error| static assertion failed: result type must be constructible from value type of input range

So it seems that Person first is correctly created, but the error is coming from when make_unique<Person>(first) is handling the unique_ptr of first.actions. Maybe. I'm not following the process of why declaration is triggering the uninitialized_copy() merely through lack of understanding, and though there's reams of similar questions around unique_ptr, I find no direct references to the "nesting" thing I've got going on and 4 hours on this is about enough before resorting to asking here.

Not necessarily after a full solution, but some hints that will get me looking at the right direction would be much appreciated. Newb-level speak would be appreciated :-)

Thanks in anticipation.

Edit: Code snippet changed to be full and compilable using gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0

My bad - vi coughed up the same make_unique() error as before, but compiling throws other errors - will not fix as question has been fully answered

CodePudding user response:

std::vector<std::unique_ptr<Action>> is not copyable because std::unique_ptr<Action> is not copyable.

std::make_unique<Person>(first) tries to copy first.

This can be fixed by moving (std::make_unique<Person>(std::move(first))), but you can also forgo the intermediate local entirely:

entities.push_back(std::make_unique<Person>(*this));
  • Related