问题 为什么不再允许从unique_ptr数组创建shared_ptr?


cppreference

在C ++ 11和C ++ 14中,构造一个是有效的 std::shared_ptr<T> 从   一个 std::unique_ptr<T[]>

std::unique_ptr<int[]> arr(new int[1]);
std::shared_ptr<int> ptr(std::move(arr));

自从 shared_ptr 获得它的删除(a    std::default_delete<T[]> 来自 unique_ptr,阵列会   正确解除分配。

在C ++ 17中不再允许这样做。而是数组形式    std::shared_ptr<T[]> 应该使用。

为什么在C ++ 17中不允许这样做?发生了什么变化?


10806
2018-04-09 09:09


起源

如果你想要一些读数: open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0414r2.html - Holt


答案:


p0497r0

unique_ptr中shared_ptr构造的约束不正确

[...]

根据实施经验,我认为正确的形式是:

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

“兼容”检查可防止不受欢迎的转换 unique_ptr<T[]> 至 shared_ptr<T> 并且“可转换为”检查确保了结果 unique_ptr<Y, D>::get() 可以存储在 shared_ptr 并返回 shared_ptr<T>::get()

换句话说,这是故意无效的,因为它不应该是有效的,而不仅仅是其他变化的副作用。

这对我来说很有意义。 shared_ptr<T> 很可能被其他程序员读作只指向一个程序员 T 目的。要求程序员使用 shared_ptr<T[]> 当他们想要多个 T 对象导致更可读的代码。

注意:此正确的表单不在标准中。然而,理由是部分地评论标准中的内容。


14
2018-04-09 09:46



我认为这是合理的 unique_ptr<T[]> 不应该转换成 shared_ptr<T>。但它是否值得打破向后兼容性? - ikh
@ikh请记住,最初,有 没有 检查,这意味着通用代码无法使用SFINAE来检查隐式转换 std::unique_ptr<int> 至 std::shared_ptr<std::string> 是胡说八道。 (static_assert(std::is_convertible<std::unique_ptr<std::string>, std::shared_ptr<int>>(), ""); 被要求通过。)如果调整措辞以纠正这一点,是的,我认为值得立即采取行动。
@ikh如果我们需要特定的转换,共享的ptr别名构造函数也是一种解决方法。喜欢 auto tmp=shared_ptr<T[]>( std::move(up) ); auto sp=shared_ptr<T>( tmp.get(), tmp ); - Yakk - Adam Nevraumont