Reputation: 4513
I explored this topic in Coliru with the following input command:
g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
The test can be found here, but I have posted the code below. I used int
in my example, as it's a basic type.
#include <iostream>
#include <memory>
struct Foo{
Foo() :
a_{0}, b_{1}, c_{-1}, combination_{0.5} {}
int
a_,
b_,
c_;
double
combination_;
};
int main()
{
//int
// *unManagedArray = new int[16];
std::unique_ptr<int[]>
uniqueArrayOrigin = std::make_unique<int[]>(16);
std::shared_ptr<int>
// works but needs call to new
// sharedSingleTest{unManagedArray, std::default_delete<int[]>{}};
// works, does not require call to new
sharedSingleUnique = std::make_unique<int[]>(16);
// compilation error (conversion to non-scalar type)
// sharedSingleDerived = uniqueArrayOrigin;
// std::shared_ptr<int[]>
// compilation errors
// sharedArrayTest{unManagedArray, std::default_delete<int[]>{}};
// compilation error (conversion to non-scalar type)
// sharedArrayUnique = std::make_unique<int[]>(16);
// compilation error (conversion to non-scalar type)
// sharedArrayDerived = uniqueArrayOrigin;
std::shared_ptr<Foo>
// works: specified overload of operator= for shared_ptr
nonArrayTest = std::make_unique<Foo>();
std::cout << "done!\n";
}
I have looked around on SO for answers, but only turned up references to the implementation of std::shared_ptr
not having a specialization, and that this largely was because no one bothered to give a proper proposal to the standards committee on the subject.
I am curious, because I would interpret 4th overload of operator=
, std::shared_ptr<T[]>.operator=(std::unique_ptr<T[], Deleter>&&)
on cppreference to indicate that such syntax is legal-- T[]
and T[]
are the same type regardless of the state of specializations for array types for std::shared_ptr
, after all.
Furthermore, this syntax only appears to work on the product of std::make_unique<T[]>
, and not a unique pointer object, which goes against my understanding of the topic--shouldn't the calls be effectively the same, though one moves an existing object, and the other, well, moves an object that's just been created? I would expect the only difference between them would be the invalid std::unique_ptr<T[]>
after the function call in the first case.
As a side note, I assume that since there is a way of constructing a dynamically-allocated array into a shared_ptr
that does not require the use of new
, I should prefer it to the messier and exception-unsafe call to new T[N]
?
tl;dr:
operator=
does not work at all between std::shared_ptr<T[]>
and std::unique_ptr<T[]>
though I would expect it to work. Why?T[]
to T
to be a source of compilation errors between the unique and shared pointers. Why does this work?operator=
works between std::shared_ptr<T>
and std::make_unique<T[]>
but not std::unique_ptr<T[]>
. Why?operator= std::make_unique<T[]>(N)
?Why aren't I using?
Upvotes: 7
Views: 559
Reputation: 60979
§20.8.2.2.1/28:
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
Remark: This constructor shall not participate in overload resolution unless
unique_ptr<Y, D>::pointer
is convertible toT*
.
However, unique_ptr<U[]>::pointer
is actually U*
, while shared_ptr<U[]>
's T*
is U(*)[]
; And U*
cannot be converted to U(*)[]
, hence the overload is never considered.
Upvotes: 5