Не удается вернуть объект с unique_ptr в std::vector

#c #unique-ptr #move-constructor

#c #уникальный-ptr #переместить-конструктор

Вопрос:

Я пытаюсь создать объект, который может содержать указатель на его родительский элемент и вектор на его дочерние элементы.

Проблема в том, что когда я пытаюсь поместить объект с unique_back или push_back в дочерний вектор, я получаю

Error C2280 'Entity::Entity(const Entity amp;)': attempting to reference a deleted function

Из-за того, что у меня есть unique_ptr в сущности.

Я думал, что добавление конструктора перемещения решит эту проблему, но этого не произошло.

Я включил минимальный проверяемый пример, пригодный для выполнения, здесь ниже.

 #include <iostream>
#include <vector>
#include <memory>

using namespace std;

struct Entity
{
   //////// data
   unique_ptr<Entity> mParent;
   std::vector<Entity> mChildren;

   //////// ctors
   // default
   Entity() = default;
   // move
   Entity(Entity amp;amp; entity): mParent{std::move(entity.mParent)}{}

   //////// functions
   void add_child(Entity const amp;amp; entity)
   {
       mChildren.emplace_back(entity); // COMMENT OUT THIS LINE FOR FUNCTIONAL CODE
       //Error  C2280 'Entity::Entity(const Entity amp;)': attempting to reference a deleted function in... includexmemory0 881
   };
};

int main()
{
   Entity entity;
   entity.add_child(Entity());
   return 0;
}
  

Ответ №1:

Отбросьте const :

 void add_child(Entity amp;amp; entity)
  

и использовать:

 mChildren.push_back(std::move(entity));
  

Применение этих двух изменений выше привело к компиляции для меня.

Объяснение: Вы хотите вызвать void push_back( Tamp;amp; value ); (или аналогично с emplace_back ) в vector<T> , где T находится Entity . Другая перегрузка — это void push_back( const Tamp; value ); перегрузка, которая не компилируется, потому что ее реализация (тело метода) пытается вызвать конструктор копирования T , а Entity конструктора копирования нет. Реализация void push_back( Tamp;amp; value ); вызывает конструктор перемещения T и Entity имеет конструктор перемещения, поэтому он компилируется.

Чтобы убедиться, что это void push_back( Tamp;amp; value ); вызвано, вы хотите передать Entityamp;amp; в push_back . Для этого вам нужны оба изменения, описанные выше. Без любого из них entity не может быть преобразован в Entityamp;amp; .

Смотрите также https://en.cppreference.com/w/cpp/container/vector/push_back.

Комментарии:

1. @user4581301: Удаление const , но не добавление std::move , не привело к компиляции для меня.

2. Да, вам нужно std::move . Ссылка на rvalue сама по себе является выражением lvalue.

3. С моей стороны это полубредовая попытка. меня интересовало изменение с emplace_back на push_back .

4. @user4581301 В этом случае они эквивалентны. std::vector::push_back имеет Tamp;amp; перегрузку, и оба будут создавать экземпляр на месте с использованием конструктора перемещения.

5. Я знаю. Я уже взломал код запрашивающего, чтобы добавить в std:: move и забыл, что я это сделал. Все, что мне нужно было, чтобы заставить его работать в тот момент, это удалить const . Когда я снова посмотрел на код запрашивающего, я заметил, что я сделал.