Why does std :: shared_ptr <T> = std :: unique_ptr <T []> compile, but std :: shared_ptr <T []> = std :: unique_ptr <T []> not?

I studied 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 posted the code below. I used int in my example since it is a base 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 looked at SO for answers, but only raised links to the std::shared_ptr implementation without specialization, and that this was mainly because there wasn’t one who bothered to give the right proposal to the standardization committee on this issue.

I am curious because I would interpret the 4th overload of operator= , std::shared_ptr<T[]>.operator=(std::unique_ptr<T[], Deleter>&&) on cppreference to indicate what the syntax is is legal - T[] and T[] are the same, regardless of the state of the specializations for array types for std::shared_ptr .

In addition, this syntax only works on the product std::make_unique<T[]> , and not on a unique pointer object, which contradicts my understanding of the topic - should these calls not be the same, although one existing object and the other are good moves an object that has just been created? I would expect the difference between them to be invalid std::unique_ptr<T[]> after calling the function in the first case.

As a side note, I assume that since there is a way to build a dynamically allocated array in shared_ptr that does not require the use of new , should I prefer it for messier and the exception is the unsafe call new T[N] ?

TL; DR:

  • operator= doesn't work at all between std::shared_ptr<T[]> and std::unique_ptr<T[]> , although I would expect it to work. Why?
  • In any case, I would expect the type conversion from T[] to T become a source of compilation errors between unique and generic pointers. Why does it work?
  • operator= works between std::shared_ptr<T> and std::make_unique<T[]> but not std::unique_ptr<T[]> . Why?
  • I correctly assume in cases where a dynamically allocated shared array is required, but where I do not want to use boost or vector (reasons below) should I call operator= std::make_unique<T[]>(N) ?

Why am I not using?

  • Boost : Not yet approved for use by my company, and I don’t know when or when I will get permission to use it.
  • Arrays I have to determine the size of this array at runtime.
  • Vectors . I work on a real-time signal processing system and prefer to avoid dereferencing extra pointers. I also tried to avoid the inclusion of extraneous libraries in my header files (this was due to the exchange of data between the reading and writing subsystems). However, in the end, I decided to optimize this later if it matters (premature optimization ...) and bite the bullet. However, the question remains.
+7
c ++ stl g ++ c ++ 14
source share
1 answer

Β§20.8.2.2.1 / 28:

 template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r); 

Note : this constructor should not be involved in overload resolution if unique_ptr<Y, D>::pointer not converted to T* .

However, unique_ptr<U[]>::pointer is actually U* , and shared_ptr<U[]> T* is U(*)[] ; And U* cannot be converted to U(*)[] , so congestion is never considered.

+5
source share

All Articles