Reputation: 127
I'm having some confusion towards using the copy constructor and copy assignment operator while dealing with unique_ptr
. I would really appreciate it if you could share some insights!
Now we have class B
.
Struct C
is a member of class B
.
Struct C
has a std::unique_ptr<A>
member.
A.h
class A {
public:
A(int* id);
A(const A& other);
~A() override;
private:
Microsoft::WRL::ComPtr<int> id_;
};
A.cpp
A::A(int* id) : id_(id) {
}
A::A(
const A& 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>& input_a);
C(const C& other);
C& operator=(const C&);
~C();
int pad_id;
Microsoft::WRL::ComPtr<int> id;
std::unique_ptr<A> a;
};
B();
B(const B&) = delete;
B& operator=(const B&) = 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>& input_a)
: pad_id(input_pad_id), id(input_id),
a(std::move(input_a)) {}
B::C::~C() = default;
B::C::C(const C& other) = default;
B::C& B::C::operator=(const B::C& other) = default;
While building I got this error log:
error: no matching member function for call to 'push_back'
c_item_.push_back({pad_id, id, nullptr});
~~~~~~~~~~^~~~~~~~~
../../buildtools/third_party/libc++/trunk/include\vector(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/include\vector(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_type&& __x);
^
../B.cc(311,5): error: defaulting this copy constructor would delete it after its first declaration
B::C::C(const C& other) = default;
^
../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/include\memory(2528,3): note: copy constructor is implicitly deleted because 'unique_ptr<B>' has a user-declared move constructor
unique_ptr(unique_ptr&& __u) _NOEXCEPT
^
../B.cc(315,65): error: defaulting this copy assignment operator would delete it after its first declaration
B::C& B::C::operator=(const B::C& other) = default;
^
../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/include\memory(2528,3): note: copy assignment operator is implicitly deleted because 'unique_ptr<A>' has a user-declared move constructor
unique_ptr(unique_ptr&& __u) _NOEXCEPT
^
In this case, how could I solve this compile error by making the code use the copy constructor that is available while unique_ptr<A>
has a user-declared
move constructor?
Upvotes: 1
Views: 1406
Reputation: 4201
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 &&) = default;
not_unique_ptr(not_unique_ptr const& init)
: base{std::make_unique<A>(*init)};
explicit not_unique_ptr(base && b)
: base{std::move(b)}{};
auto& operator=(not_unique_ptr &&) = default;
auto& operator=(base&& rhs){
base&{*this}=std::move(rhs);
};
auto& operator=(not_unique_ptr const& rhs){
base&{*this}=base&&{not_unique_ptr{rhs}};
};
};
Upvotes: 0
Reputation: 66922
Let me remove some formatting:
error: defaulting this copy constructor would delete it...
C(const C& 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
has no copy constructor, because it's unique. It can't be copied. So the default copy constructor for anything that contains a std::unique_ptr
is deleted. So your C
class has no copy constructor. Also, you never gave it a move constructor.
And std::vector
insertion methods (aka push_back) might have to resize, so it has to move or copy it's elements, but C
has no copy or move constructor, so you're getting a compiler error.
So the solution is to give C
either a working copy constructor, and/or a move constructor. If it makes sense for whatever your C
is, you could give it a copy constructor by making a deep copy of the pointed at A
, but I don't know what A
is, so I can't say for certain. It almost always makes sense to create a move constructor though.
Upvotes: 4