Как реализовать конструктор копирования для класса, который имеет переменную-член unique_ptr
? Я рассматриваю только C++ 11.Копировать конструктор для класса с unique_ptr
ответ
Поскольку unique_ptr
не может использоваться совместно, вам необходимо либо глубоко скопировать его содержимое, либо преобразовать unique_ptr
в shared_ptr
.
class A
{
std::unique_ptr<int> up_;
public:
A(int i) : up_(new int(i)) {}
A(const A& a) : up_(new int(*a.up_)) {}
};
int main()
{
A a(42);
A b = a;
}
Вы можете, как уже упоминалось NPE, используйте Move-CTOR вместо копирования CTOR, но это привело бы к различной семантикой вашего класса. Движение-т е р должны были бы сделать член как движимое явно через std::move
:
A(A&& a) : up_(std::move(a.up_)) {}
Имея полный набор необходимых операторов также приводит к
A& operator=(const A& a)
{
up_.reset(new int(*a.up_));
return *this,
}
A& operator=(A&& a)
{
up_ = std::move(a.up_);
return *this,
}
Если вы хотите использовать свой класс в std::vector
, вам в основном нужно решить, должен ли вектор быть единственным владельцем объекта, и в этом случае было бы достаточно сделать класс подвижным, но не скопированным. Если вы не укажете copy-ctor и присваиваете копии, компилятор будет руководствоваться тем, как использовать std :: vector с типами перемещения.
Daniel Frey упомянуть о решении копирования, я бы говорить о том, как переместить unique_ptr
#include <memory>
class A
{
public:
A() : a_(new int(33)) {}
A(A &&data) : a_(std::move(data.a_))
{
}
A& operator=(A &&data)
{
a_ = std::move(data.a_);
return *this;
}
private:
std::unique_ptr<int> a_;
};
Они называются шаг конструктора и переместить назначение
вы могли бы использовать их, как это
int main()
{
A a;
A b(std::move(a)); //this will call move constructor, transfer the resource of a to b
A c;
a = std::move(c); //this will call move assignment, transfer the resource of c to a
}
Вам нужно обернуть a и c с помощью std :: move, потому что у них есть имя std :: move сообщает компилятору, чтобы преобразовать значение в ссылка Rvalue независимо от параметров В техническом смысле, станд :: ход аналогии с чем-то вроде «станд :: RValue»
После перемещения, то ресурс unique_ptr является переход к другой unique_ptr
Есть много тем, которые документируют ссылку rvalue; this is a pretty easy one to begin with.
Edit:
Двинутый объект shall remain valid but unspecified state.
C++ праймер 5, CH13 также дают очень хорошее объяснение о том, как «движение» объект
так что происходит с объектом 'a' после вызова std :: move (a) в конструкторе перемещения' b'? Это просто совершенно недействительно? –
Попробуйте этот помощник, чтобы создать глубокие копии, и справиться, когда источник unique_ptr равна нулю.
template< class T >
std::unique_ptr<T> copy_unique(const std::unique_ptr<T>& source)
{
return source ? std::make_unique<T>(*source) : nullptr;
}
Например:
class My
{
My(const My& rhs)
: member(copy_unique(rhs.member))
{
}
// ... other methods
private:
std::unique_ptr<SomeType> member;
};
Будет ли она правильно копировать, если источник указывает на что-то, полученное от T? –
@RomanShapovalov Нет, возможно, нет, вы бы получили нарезку. В этом случае решение, вероятно, будет заключаться в добавлении к вашему типу виртуального метода uniqueone_ptr
Нет ли уникальных указателей/облачных указателей в C++ или более мощных библиотеках с встроенными функциями глубокой копии? Было бы неплохо не создавать собственные конструкторы копирования и т. Д.для классов, которые используют эти интеллектуальные указатели, когда мы хотим, чтобы поведение с глубокой копией часто случалось. Просто интересуюсь. –
Обычный случай для одного, чтобы в классе с unique_ptr
, чтобы иметь возможность использовать наследование (в противном случае простой объект будет делать, а, см RAII). Для этого случая нет соответствующего ответа в этой ветке до сих пор.
Итак, вот отправная точка:
struct Base
{
//some stuff
};
struct Derived : public Base
{
//some stuff
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
};
... и цель, как было сказано, чтобы сделать Foo
воспроизводимую.
Для этого необходимо сделать глубокую копию содержащегося указателя, чтобы гарантировать, что производный класс скопирован правильно.
Это может быть достигнуто путем добавления следующего кода:
struct Base
{
//some stuff
auto clone() const { return std::unique_ptr<Base>(clone_impl()); }
protected:
virtual Base* clone_impl() const = 0;
};
struct Derived : public Base
{
//some stuff
protected:
virtual Derived* clone_impl() const override { return new Derived(*this); };
};
struct Foo
{
std::unique_ptr<Base> ptr; //points to Derived or some other derived class
//rule of five, but a user-defined dtor is not necessary due to unique_ptr
Foo(Foo const& other) : ptr(other.ptr->clone()) {}
Foo(Foo && other) = default;
Foo& operator=(Foo const& other) { ptr = other.ptr->clone(); return *this; }
Foo& operator=(Foo && other) = default;
};
Там в основном две вещи, здесь происходит:
Первое добавление копирования и перемещения конструкторами, которые неявно удаляются в
Foo
, поскольку конструктор копированияunique_ptr
удален. Конструктор перемещения может быть добавлен просто= default
..., который позволяет компилятору знать, что обычный конструктор перемещения должен удалить не (это работает, так какunique_ptr
уже имеет конструктор перемещения, который может быть использован в этом случае) ,Для конструктора копирования
Foo
нет такого механизма, как нет конструктора копированияunique_ptr
. Итак, нужно построить новыйunique_ptr
, заполнить его копией исходного указателя и использовать его как члена скопированного класса.В случае, если наследование задействовано, копия оригинала должна быть выполнена тщательно. Причина в том, что выполнение простой копии с помощью
std::unique_ptr<Base>(*ptr)
в приведенном выше коде приведет к разрезанию, т. Е. Будет только скопирован только базовый компонент объекта, а производная часть отсутствует.Чтобы избежать этого, копия должна быть выполнена с помощью шаблона клонирования. Идея состоит в том, чтобы сделать копию через виртуальную функцию
clone_impl()
, которая возвращаетBase*
в базовом классе. В производном классе, однако, он расширяется с помощью ковариации, чтобы вернутьDerived*
, и этот указатель указывает на вновь созданную копию производного класса. Базовый класс может затем получить доступ к этому новому объекту с помощью указателя базового классаBase*
, обернуть его вunique_ptr
и вернуть его через действительную функциюclone()
, которая вызывается извне.
- 1. Копировать конструктор класса конкретизации
- 2. Копировать конструктор для передачи права собственности на unique_ptr
- 3. Копировать конструктор для класса с unique_ptr в абстрактный класс как член
- 4. Копировать конструктор, вызывающий конструктор копирования другого класса
- 5. Почему я могу копировать unique_ptr?
- 6. Копировать конструктор для класса с элементами данных shared_ptr?
- 7. Конструктор шаблона C++ с уникальным элементом unique_ptr
- 8. Копировать конструктор?
- 9. Копировать конструктор в python?
- 10. Копировать конструктор, вызванный из производного класса
- 11. Передача контейнера unique_ptr в конструктор?
- 12. Копировать конструктор и конструктор по умолчанию
- 13. Копировать конструктор связанного списка
- 14. Копировать конструктор с адресом mmap
- 15. Копировать конструктор без аргументов
- 16. Копировать конструктор и operator = для динамического массива внутри класса
- 17. Конструктор: unique_ptr + движение против shared_ptr
- 18. Инициализация C++ unique_ptr через конструктор
- 19. Копировать конструктор для 2d массива C++
- 20. Копировать конструктор в C++?
- 21. Копировать конструктор не называется?
- 22. Определенный пользователем Копировать конструктор
- 23. unique_ptr конструктор с пользовательскими Deleter удаляется
- 24. Копировать конструктор ярлык
- 25. Копировать конструктор над присвоением
- 26. Копировать конструктор «структура атомного»
- 27. Копировать конструктор C++ weird behavoir?
- 28. Копировать конструктор не работает?
- 29. Копировать конструктор или = оператор?
- 30. Копировать конструктор. Он работает
Ну, что вы хотите, чтобы конструктор копирования выполнял? –
Я читал, что unique_ptr непокрываем. Это заставляет меня задаться вопросом, как использовать класс, который имеет переменную-член unique_ptr в 'std :: vector'. – codefx
Я думаю, что после копирования, если у нас есть 2 объекта с уникальными указателями, указывающими на одно и то же местоположение (объект), тогда это имеет смысл? Они должны быть уникальными. Если класс с указателем реализует конструктор копирования, то этот указатель должен быть общим указателем, я считаю не уникальным указателем. –