`unique_ptr< T const [] >` 是不是应该接受 `T*` 构造函数参数?

Posted

技术标签:

【中文标题】`unique_ptr< T const [] >` 是不是应该接受 `T*` 构造函数参数?【英文标题】:Should `unique_ptr< T const [] >` accept a `T*` constructor argument?`unique_ptr< T const [] >` 是否应该接受 `T*` 构造函数参数? 【发布时间】:2012-01-21 19:22:42 【问题描述】:

代码:

#include <memory>
using namespace std;

struct T ;

T* foo()  return new T; 
T const* bar()  return foo(); 

int main()

    unique_ptr< T const >       p1( bar() );        // OK
    unique_ptr< T const [] >    a1( bar() );        // OK

    unique_ptr< T const >       p2( foo() );        // OK
    unique_ptr< T const [] >    a2( foo() );        // ? this is line #15

Visual C++ 10.0 和 MinGW g++ 4.4.1 的示例错误:

[d:\开发\测试] > cl foo.cpp foo.cpp foo.cpp(15) : 错误 C2248: 'std::unique_ptr<_ty>::unique_ptr' : 无法访问在类 'std::unique_ptr<_ty>' 中声明的私有成员 和 [ _Ty=常量 T [] ] C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\INCLUDE\memory(2509) :请参阅 'std::unique_ptr<_ty>::unique_ptr' 的声明 和 [ _Ty=常量 T [] ] [d:\开发\测试] > g++ foo.cpp -std=c++0x c:\program files (x86)\codeblocks\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/unique_ptr.h:在函数'int main()'中: c:\program 文件 (x86)\codeblocks\mingw\bin\../lib/gcc/mingw32/4.4.1/include/c++/bits/unique_ptr.h:379: 错误:已删除函数 'std::unique_ptr::unique_ptr(_Up*, typename std::enable_if<:is_convertible::value void>::type*) [with _Up = T, _Tp = const T, _Tp_Deleter = std:: default_delete]' foo.cpp:15:错误:在这里使用 [d:\开发\测试] > _

在我看来,数组版本应该接受与非数组版本相同的隐式常量添加。

不同之处在于数组版本不应该接受指向派生类的指针,而这显然是上面的机制。

代码有效吗?

如果代码形式上无效,标准的措辞是否反映了意图(即,DR 是否合适)?

如果第一个为否,第二个为“是”,意图是否有缺陷(即,DR 是否合适)?

【问题讨论】:

【参考方案1】:

缺陷报告可能是合适的。 §20.7.1.3.1 说,

explicit unique_ptr(pointer p) noexcept;
unique_ptr(pointer p, see below d) noexcept;
unique_ptr(pointer p, see below d) noexcept;

这些构造函数的行为与主模板中的相同,只是它们不接受可转换为指针的指针类型。 [注意:一种实现技术是创建这些成员的私有模板化重载。 ——尾注]

这个想法显然是为了防止不适用于数组的派生到基的转换。但它是不具体的,也禁止 cv-qualification 转换。也许应该将其更改为禁止指针转换(第 4.10 节),而不是所有的指针转换。

【讨论】:

“可转换为指针的指针类型” - 真的很挑剔,这种语言难道不是不正确的吗? pointer 是一个指针类型,它可以转换为指针(例如在描述概念时,如果某个函数返回一个“可转换为 T”的类型,并不意味着它不能是 T 本身)。但我不认为意图是除了pointer 以及指向派生类型的指针;-) 我将 difect riport 发布到 csc++,但可能需要一些时间才能出现......所以,仅供参考,我还在 §20.7.1.3/ 中引用了我认为的意图/理由1 第二个破折号,“指向从 T 派生的类型的指针被构造函数和重置拒绝”:-) 这对我来说似乎是个缺陷。请跟进:open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#submit_issue。我已经在 libc++ (libcxx.llvm.org) 中实现了一个解决方案。做对比我想象的更难! @HowardHinnant:好的,完成。我抄送给你,但只是到一个我用谷歌搜索的电子邮件地址,可能太旧了。我发生了崩溃,所以所有旧的电子邮件地址列表都消失了,我在 SO 上看不到任何电子邮件地址。干杯, 这已在 C++ 标准的工作草案中得到修复。在 C++17 之前它不会是“官方的”,但供应商通常不会等待新的正式标准来实施 DR 修复。对于好奇,@Alf 提交的缺陷报告是LWG 2118。

以上是关于`unique_ptr< T const [] >` 是不是应该接受 `T*` 构造函数参数?的主要内容,如果未能解决你的问题,请参考以下文章

const unique_ptr 的propagate_const

将 std::unique_ptr 类成员标记为 const

unique_ptr<T> 和 unique_ptr<T>&& 之间的区别 [重复]

为啥 unique_ptr<T> 不能从 T* 构造?

两个 unique_ptr<T> 的无锁交换

来自 T* 的 std::unique_ptr<T> 的构造函数显式背后的原因是啥?