【问题标题】:libc++ doesn't allow construction of shared_ptr<T> from unique_ptr<T[]>libc++ 不允许从 unique_ptr<T[]> 构造 shared_ptr<T>
【发布时间】:2017-03-06 00:17:28
【问题描述】:

是否有任何理由为什么以下内容在 c++11(或更高版本)中不起作用?

#include <memory>

int main()
{
    auto up = std::unique_ptr<int[]>(new int[5]{});
    auto sp = std::shared_ptr<int>(std::move(up));
}

我的期望是这将使用列出的第 13 个构造函数here at cppreference.com

https://gcc.godbolt.org/ 检查时,Visual Studio 和 gcc 会毫无问题地编译它,但是 clang++ - 或者更具体地说是 libc++ (-stdlib=libc++) - 会引发一个复杂的错误:

<source>:6:13: error: no matching conversion for functional-style cast from 'typename remove_reference<unique_ptr<int const[], default_delete<int const[]> > &>::type' (aka 'std::__1::unique_ptr<int const[], std::__1::default_delete<int const[]> >') to 'std::shared_ptr<const int>'
auto sp = std::shared_ptr<const int>(std::move(up));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[..]c++/v1/memory:3900:23: note: candidate constructor not viable: no known conversion from 'typename remove_reference<unique_ptr<int const[], default_delete<int const[]> > &>::type' (aka 'std::__1::unique_ptr<int const[], std::__1::default_delete<int const[]> >') to 'nullptr_t' for 1st argument
_LIBCPP_CONSTEXPR shared_ptr(nullptr_t) _NOEXCEPT;
^
[..]c++/v1/memory:3914:5: note: candidate constructor not viable: no known conversion from 'typename remove_reference<unique_ptr<int const[], default_delete<int const[]> > &>::type' (aka 'std::__1::unique_ptr<int const[], std::__1::default_delete<int const[]> >') to 'const std::__1::shared_ptr<const int>' for 1st argument
shared_ptr(const shared_ptr& __r) _NOEXCEPT;
^
[..]c++/v1/memory:3922:5: note: candidate constructor not viable: no known conversion from 'typename remove_reference<unique_ptr<int const[], default_delete<int const[]> > &>::type' (aka 'std::__1::unique_ptr<int const[], std::__1::default_delete<int const[]> >') to 'std::__1::shared_ptr<const int>' for 1st argument
shared_ptr(shared_ptr&& __r) _NOEXCEPT;
^
[..]c++/v1/memory:3902:18: note: candidate template ignored: could not match '_Yp *' against 'typename remove_reference<unique_ptr<int const[], default_delete<int const[]> > &>::type' (aka 'std::__1::unique_ptr<int const[], std::__1::default_delete<int const[]> >')
explicit shared_ptr(_Yp* __p,
^
[..]c++/v1/memory:3917:9: note: candidate template ignored: could not match 'shared_ptr' against 'unique_ptr'
shared_ptr(const shared_ptr<_Yp>& __r,
^
[..]c++/v1/memory:3923:52: note: candidate template ignored: could not match 'shared_ptr' against 'unique_ptr'
template<class _Yp> _LIBCPP_INLINE_VISIBILITY  shared_ptr(shared_ptr<_Yp>&& __r,
^
[..]c++/v1/memory:3927:34: note: candidate template ignored: could not match 'weak_ptr' against 'unique_ptr'
template<class _Yp> explicit shared_ptr(const weak_ptr<_Yp>& __r,
^
[..]c++/v1/memory:3931:9: note: candidate template ignored: could not match 'auto_ptr' against 'unique_ptr'
shared_ptr(auto_ptr<_Yp>&& __r,
^
[..]c++/v1/memory:3943:24: note: candidate template ignored: disabled by 'enable_if' [with _Yp = int const[], _Dp = std::__1::default_delete<int const[]>]
!is_lvalue_reference<_Dp>::value &&
^
[..]c++/v1/memory:3952:24: note: candidate template ignored: disabled by 'enable_if' [with _Yp = int const[], _Dp = std::__1::default_delete<int const[]>]
is_lvalue_reference<_Dp>::value &&
^
[..]c++/v1/memory:3905:9: note: candidate constructor template not viable: requires at least 2 arguments, but 1 was provided
shared_ptr(_Yp* __p, _Dp __d,
^
[..]c++/v1/memory:3908:9: note: candidate constructor template not viable: requires at least 3 arguments, but 1 was provided
shared_ptr(_Yp* __p, _Dp __d, _Alloc __a,
^
[..]c++/v1/memory:3910:26: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
template <class _Dp> shared_ptr(nullptr_t __p, _Dp __d);
^
[..]c++/v1/memory:3911:40: note: candidate constructor template not viable: requires 3 arguments, but 1 was provided
template <class _Dp, class _Alloc> shared_ptr(nullptr_t __p, _Dp __d, _Alloc __a);
^
[..]c++/v1/memory:3912:51: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
template<class _Yp> _LIBCPP_INLINE_VISIBILITY shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) _NOEXCEPT;
^
[..]c++/v1/memory:3898:23: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
_LIBCPP_CONSTEXPR shared_ptr() _NOEXCEPT;
^
1 error generated.
Compiler exited with result code 1

【问题讨论】:

标签: c++ c++11 clang++ libc++


【解决方案1】:

标准(C++17 之前)仅对第 13 个构造函数进行了如下说明:

除非unique_ptr&lt;Y, D&gt;::pointer 可转换为T*,否则此构造函数不应参与重载决议。

但是由于std::unique_ptr&lt;int[]&gt;::pointer 可以转换为int*,所以代码应该可以工作。这是 libc++ 中的一个错误。

与此同时,您可以使用以下内容:

auto sp = std::shared_ptr<int>(up.release(), up.get_deleter());

【讨论】:

  • 您是否知道是否已针对该问题提交了错误报告?
  • 我不知道。
  • C++17 标准似乎禁止它,因为Y* 不能转换为T*。 AKA int(*)[]) 无法转换为 int*
  • @EricWF:非常感谢您处理这个问题。是的,这也是我对c++17中情况的理解。
  • @MikeMB 虽然我阅读 C++17 规范的次数越多,我就越认为这是一个标准缺陷。我也会就此提出 LWG 问题。
【解决方案2】:

您的类型不同:int[] 不是 int。

【讨论】:

  • 它们不必相同(构造函数实际上是根据参数智能指针的元素类型模板化的)。但我承认我不能 100% 确定措辞是否允许从 T[] 转换为 T
  • 使用“new []”分配的指针需要使用“delete []”删除,这不是 std::shared_ptr 会做的。您的示例有 UB,而 libc++ 有助于拒绝它。
  • @EricWF 它从unique_ptr 得到正确的删除器,所以没关系。
  • @EricWF:您可以将任何删除器存储在 shared_ptr 中(它会被类型擦除),并且构造函数应该负责这一点。来自链接的网站:“构造一个 shared_ptr 来管理当前由 r 管理的对象。存储与 r 关联的删除器以供将来删除托管对象。”
  • 我的错误。感谢您的指正。我将提交一个 libc++ 错误并在有时间时修复它。 (编辑:假设我对标准的阅读与您的示例一致)。
猜你喜欢
  • 2015-08-10
  • 1970-01-01
  • 2015-07-23
  • 2017-03-19
  • 1970-01-01
  • 2018-02-02
  • 2020-10-25
  • 1970-01-01
  • 2020-08-19
相关资源
最近更新 更多