为什么 std::shared_ptr<T> = std::unique_ptr<T[]> 编译,而 std::shared_ptr<T[]> = std::unique_ptr<T[]> 不编译?

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

我使用以下输入命令在 Coliru 中探索了这个主题:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

测试可以找到here,不过我把代码贴在下面了。我在示例中使用了 int,因为它是基本类型。


#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";
}

我在 SO 上四处寻找答案,但只发现 references 没有专业化的 std::shared_ptr 的实施,这主要是因为没有人费心给出适当的答案就此主题向标准委员会提出建议。

我很好奇,因为我会在 cppreference 上解释 operator=std::shared_ptr<T[]>.operator=(std::unique_ptr<T[], Deleter>&&) 的第 4 次重载,以表明这种语法是合法的——T[]T[] 是毕竟,无论 std::shared_ptr 的数组类型的特化状态如何,都是相同的类型。

此外,此语法似乎只适用于 std::make_unique<T[]> 的乘积,而不适用于唯一的指针对象,这与我对该主题的理解不符——调用实际上不应该相同,尽管一个移动现有对象,而另一个移动刚刚创建的对象?我希望它们之间的唯一区别是第一种情况下函数调用后的无效 std::unique_ptr<T[]>

作为旁注,我假设因为有一种方法可以将动态分配的数组构造成 shared_ptr 而不需要使用 new,我应该更喜欢它对 new T[N]?

的更混乱和异常不安全的调用

tl;博士:

  1. operator=std::shared_ptr<T[]>std::unique_ptr<T[]> 之间根本不起作用,尽管我希望它能起作用。为什么?
  2. 如果有的话,我希望从 T[]T 的类型转换是唯一指针和共享指针之间编译错误的来源。为什么这样做有效?
  3. operator=std::shared_ptr<T>std::make_unique<T[]> 之间有效,但在 std::unique_ptr<T[]> 之间无效。为什么?
  4. 我假设在需要动态分配的共享数组的情况下是否正确,但我不想使用 boost 或向量(原因如下)我应该调用 operator= std::make_unique<T[]>(N)?

为什么我没有使用?

§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 to T*.

然而,unique_ptr<U[]>::pointer实际上是U*,而shared_ptr<U[]>T*U(*)[];并且 U* 无法转换为 U(*)[],因此从不考虑重载。