#c #class #copy-constructor #copy-assignment
#c #класс #copy-constructor #копирование-присвоение
Вопрос:
У меня возникает некоторая путаница при использовании конструктора копирования и оператора присваивания копирования при работе unique_ptr
. Я был бы очень признателен, если бы вы могли поделиться некоторыми соображениями!
Теперь у нас есть class B
.
Struct C
является членом class B
.
Struct C
имеет std::unique_ptr<A>
член.
A.h
class A {
public:
A(int* id);
A(const Aamp; other);
~A() override;
private:
Microsoft::WRL::ComPtr<int> id_;
};
A.cpp
A::A(int* id) : id_(id) {
}
A::A(
const Aamp; other) {
id_ = other.id_;
}
A::~A() = default;
B.h
class B {
public:
struct C{
public:
C(
int input_pad_id,
Microsoft::WRL::ComPtr<int> input_id,
std::unique_ptr<A>amp; input_a);
C(const Camp; other);
Camp; operator=(const Camp;);
~C();
int pad_id;
Microsoft::WRL::ComPtr<int> id;
std::unique_ptr<A> a;
};
B();
B(const Bamp;) = delete;
Bamp; operator=(const Bamp;) = delete;
~B() override;
private:
std::vector<C> c_item_;
};
B.cpp
B::B() = default;
B::~B() = default;
/* omitting some code related to operation logic */
...
c_item_.push_back({pad_id, id, nullptr});
...
/* omitting some code related to operation logic */
B::C::C(int input_pad_id,
Microsoft::WRL::ComPtr<int> input_id,
std::unique_ptr<A>amp; input_a)
: pad_id(input_pad_id), id(input_id),
a(std::move(input_a)) {}
B::C::~C() = default;
B::C::C(const Camp; other) = default;
B::Camp; B::C::operator=(const B::Camp; other) = default;
При сборке я получил этот журнал ошибок:
error: no matching member function for call to 'push_back'
c_item_.push_back({pad_id, id, nullptr});
~~~~~~~~~~^~~~~~~~~
../../buildtools/third_party/libc /trunk/includevector(711,36): note: candidate function not viable: cannot convert initializer list argument to 'const std::__vector_base<B::C, std::allocator<B::C>>::value_type' (aka 'const B::C')
_LIBCPP_INLINE_VISIBILITY void push_back(const_reference __x);
^
../../buildtools/third_party/libc /trunk/includevector(714,36): note: candidate function not viable: cannot convert initializer list argument to 'std::vector<B::C>::value_type' (aka 'B::C')
_LIBCPP_INLINE_VISIBILITY void push_back(value_typeamp;amp; __x);
^
../B.cc(311,5): error: defaulting this copy constructor would delete it after its first declaration
B::C::C(const Camp; other) = defau<
^
../B.h(33,46): note: copy constructor of 'C' is implicitly deleted because field 'c_item' has a deleted copy constructor
std::unique_ptr<C> c_item;
../../buildtools/third_party/libc /trunk/includememory(2528,3): note: copy constructor is implicitly deleted because 'unique_ptr<B>' has a user-declared move constructor
unique_ptr(unique_ptramp;amp; __u) _NOEXCEPT
^
../B.cc(315,65): error: defaulting this copy assignment operator would delete it after its first declaration
B::Camp; B::C::operator=(const B::Camp; other) = defau<
^
../B.h(33,46): note: copy assignment operator of 'C' is implicitly deleted because field 'c_item' has a deleted copy assignment operator
std::unique_ptr<A> a;
../../buildtools/third_party/libc /trunk/includememory(2528,3): note: copy assignment operator is implicitly deleted because 'unique_ptr<A>' has a user-declared move constructor
unique_ptr(unique_ptramp;amp; __u) _NOEXCEPT
^
В этом случае, как я мог бы решить эту ошибку компиляции, заставив код использовать конструктор копирования, который доступен, пока unique_ptr<A>
имеет объявленный пользователем
конструктор перемещения?
Комментарии:
1. Если вам нужна
unique_ptr
оболочка, подобная оболочке, которая предоставляет возможности копирования, ее можно написать с нуля (или создать класс, содержащий astd::unique_ptr
, но обеспечивающий копирование с помощью определяемого пользователем оператора копирования ctor / присваивания). Сложно заставить его работать во всех тех же ситуациях,unique_ptr
что и a, но если это не нужно — нет проблем.
Ответ №1:
Позвольте мне удалить некоторое форматирование:
error: defaulting this copy constructor would delete it...
C(const Camp; other) = default;
...because copy constructor of 'C' is implicitly deleted because field 'c_item' has a deleted copy constructor
std::unique_ptr<C> c_item;
std::unique_ptr
не имеет конструктора копирования, потому что он уникален. Его нельзя скопировать. Таким образом, конструктор копирования по умолчанию для всего, что содержит a std::unique_ptr
, удаляется. Итак, в вашем C
классе нет конструктора копирования. Кроме того, вы никогда не давали ему конструктор перемещения.
И std::vector
методы вставки (aka push_back) могут иметь изменение размера, поэтому он должен перемещать или копировать свои элементы, но C
не имеет конструктора копирования или перемещения, поэтому вы получаете ошибку компилятора.
Таким образом, решение состоит в том, чтобы предоставить C
либо рабочий конструктор копирования, и / или конструктор перемещения. Если это имеет смысл для того, что у вас C
есть, вы могли бы предоставить ему конструктор копирования, создав глубокую копию объекта, на который указано A
, но я не знаю, что A
это такое, поэтому я не могу сказать наверняка. Однако почти всегда имеет смысл создать конструктор перемещения.
Ответ №2:
template<typename X, typename D=std::default_deleter<A>, typename base=std::unique_ptr<A,D>>
struct not_unique_ptr
: base {
static_assert(std::is_same_v<base,std::unique_ptr<A,D>>);
not_unique_ptr()=default;
not_unique_ptr(not_unique_ptr amp;amp;) = default;
not_unique_ptr(not_unique_ptr constamp; init)
: base{std::make_unique<A>(*init)};
explicit not_unique_ptr(base amp;amp; b)
: base{std::move(b)}{};
autoamp; operator=(not_unique_ptr amp;amp;) = default;
autoamp; operator=(baseamp;amp; rhs){
baseamp;{*this}=std::move(rhs);
};
autoamp; operator=(not_unique_ptr constamp; rhs){
baseamp;{*this}=baseamp;amp;{not_unique_ptr{rhs}};
};
};