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

jag*_*ire 7 c++ stl g++ c++14

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

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)

测试可以在这里找到,但我已经发布了下面的代码.我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";
}
Run Code Online (Sandbox Code Playgroud)

我在SO上寻找答案,但只是提到std::shared_ptr没有专业化的实施,这主要是因为没有人费心向标准委员会提出有关该主题的正确建议.

我很好奇,因为我会解释第四次重载operator=,std::shared_ptr<T[]>.operator=(std::unique_ptr<T[], Deleter>&&)在cppreference上表示这样的语法是合法的 - 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或vector(下面的原因)我应该调用operator= std::make_unique<T[]>(N)

我为什么不用?

  • 提升:我公司尚未批准使用,我不知道何时或是否会获得批准使用它.
  • 数组:我必须在运行时确定此数组的大小.
  • 向量:我正在研究一个实时信号处理系统,并且宁愿避免额外的指针取消引用.我还试图避免在我的头文件中包含无关的库(这是用于读写子系统之间的通信)但是,我最终选择优化它,如果它很重要(过早优化......)并咬紧牙关.但问题仍然存在.

Col*_*mbo 5

§20.8.2.2.1/ 28:

template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r); 
Run Code Online (Sandbox Code Playgroud)

备注:除非unique_ptr<Y, D>::pointer可转换为,否则此构造函数不应参与重载决策T*.

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

  • @jaggedSpire唯一的区别在于从"unique_ptr <T []>"类型的左值赋值和从"unique_ptr <T []>"类型的右值赋值.类型可以选择只允许一个,或只允许另一个,而"unique_ptr"是一种使用它的类型.来自左值的赋值通常需要复制,并且不能复制"unique_ptr",或者指针不再是唯一的. (2认同)