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

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

本文关键字:std gt lt ptr shared uni 编译 为什么 unique      更新时间:2023-10-16

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

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

测试可以在这里找到,但我在下面发布了代码。我在示例中使用了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上寻找答案,但只提到了没有专业化std::shared_ptr的实施,这主要是因为没有人费心向标准委员会提出关于这个主题的适当建议。

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

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

作为旁注,我假设由于有一种方法可以将动态分配的数组构造到不需要使用newshared_ptr中,我应该更喜欢它而不是更混乱和异常不安全的调用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)

为什么我不使用?

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

§20.8.2.2.1/28:

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

备注:此构造函数不得参与重载解析 除非unique_ptr<Y, D>::pointer可转换为T*.

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