我指的是上方的3和4 std::unique_ptr<T,Deleter>::unique_ptr
,具有以下签名:
unique_ptr( pointer p, /* see below */ d1 ) noexcept;
主要是这些:
/* see below */
实际上是什么意思?std::unique_ptr
?而且,更详细:
std::unique_ptr
为模板的事实是必须提供deleter模板参数的原因?_Dp
与_Del
实际不同,这是怎么重要?在这里,我尝试解释我的推理。以上预期的一些问题也分散在文本中。
我的理解是,在C ++ 17之前的版本中,模板类型推导不适用于类,而仅适用于函数,因此在创建模板类的实例(例如)时,模板类的std::unique_ptr
所有必需(即,没有= default_type_or_value
)模板参数必须通过提供<…>
。
此外,在中/usr/include/c++/10.2.0/bits/unique_ptr.h
,我或多或少地看到了以下内容:
namespace std {
// …
template <typename _Tp, typename _Dp = default_delete<_Tp>>
class unique_ptr {
public:
// …
using deleter_type = _Dp;
// …
template<typename _Del = deleter_type, typename = _Require<is_copy_constructible<_Del>>>
unique_ptr(pointer __p, const deleter_type& __d) noexcept : _M_t(__p, __d) { }
// …
}
// …
}
构造函数本身是在type参数上进行模板化的_Del
,默认为class' deleter_type
(这是的别名_Dp
);据此我理解,如果我错了,请纠正我(*),std::unique_ptr
甚至不能利用C ++ 17的类的模板类型推导,因此_Dp
就此重载而言,模板参数仍然是强制性的(即删除对象将作为第二个参数传递给构造函数)。
既然是这种情况,我们传递给的实际类型实std::unique_ptr
参可以用引用声明符修饰,如链接页中所述。但这就是我迷路的地方,更不用说我确实看到了这一点,_Dp
并且_Del
可能会有所不同(例如,引用声明符可能会有所不同),这使我的理解更加复杂。
但是,我将复制页面的一部分,以解释各种可能的情况:
3-4)构造一个
std::unique_ptr
拥有以下对象的对象,如下所示p
初始化其存储的指针p
并初始化一个DeleterD
(取决于是否D
为引用类型)
a)如果
D
是非引用类型A
,则签名为:unique_ptr(pointer p, const A& d) noexcept; unique_ptr(pointer p, A&& d) noexcept;
b)如果
D
是左值引用类型A&
,则签名为:unique_ptr(pointer p, A& d) noexcept; unique_ptr(pointer p, A&& d) = delete;
c)如果
D
是左值引用类型const A&
,则签名为:unique_ptr(pointer p, const A& d) noexcept; unique_ptr(pointer p, const A&& d) = delete;
在所有情况下,删除器均从初始化
std::forward<decltype(d)>(d)
。如果std::is_constructible<D, decltype(d)>::value
为,则这些重载仅参与重载解析true
。
我可以解释引用文字的唯一方法如下,其中有很多疑问。
d
作为参数传递给构造函数,则必须显式将aD
作为模板参数传递给...什么?到class
和/或它的构造函数?甚至可以将模板参数传递给构造函数吗?D
可以是以下三种
A
,则意味着我们希望既可以传递一个(可能是const
)左值d
,也可以传递一个右值作为,因此这两个重载都采用const A&
和A&&
来定义。const A&
,我们想要一个手段是不能够通过一个右值作为d
,因此过载回吐A&&
被删除,因为它会绑定到右值,而超载A&
是用于instad const A&
,因为后者会绑定到右值太。const A&
,这意味着我们希望能够通过d
,所以采取超载const A&
是一个挑,而另一个回吐const A&&
的delete
技术了,因为该参数类型无法绑定到左值,并且const A&
确实const A&
从结合到右值,这将导致在一个悬空参考被存储在std::unique_ptr
(为原因这是这里)。d
?1.将其A&&
绑定到const A&
,并将3.绑定到,因此前者可以窃取资源,而后者则不能。最后但并非最不重要的一点是,链接页面还添加了特定于C ++ 17的内容:
如果通过类模板参数推导选择了这两个构造函数中的任何一个,则该程序格式不正确。
根据我的理解,这对我一点都不清楚(请参阅上面的(*)):这些构造函数如何进行类型推导?
因此,最重要的问题是:这种方式的复杂性如何std::unique_ptr<T,Deleter>::unique_ptr
对我作为程序员有用?
的解释
/* see below */
实际上是什么意思?
它为不同类型指定了构造函数的不同行为D
,其中D
类的模板参数如中所示std::unique_ptr<T, D>
。特别是,它考虑以下三种情况:
D
是“普通”值类型,例如std::unique_ptr<int, Deleter>
:A
只要A
可以用于复制/移动构造a Deleter
,我们就可以将任何类型的任何对象作为该参数传递。D
是一个非常量引用类型,例如std::unique_ptr<int, Deleter&>
:我们可以提供一个非常量左值表达式(并且只能提供一个非常量左值表达式),并提供可用于构造a的任何类型Deleter&
。(例如,这可能是派生类。)不允许将右值表达式传递给此参数,因为存储对(过期的)临时变量的引用没有意义。D
是const引用类型,例如std::unique_ptr<int, const Deleter&>
:与上述要点相同,只不过const限定的左值表达式也是合法的。请注意,在所有这些情况下,唯一的指针的类型纯粹决定D
:在A
S IN参数,只允许通过的值类型其他比D
,可用于构建它。
作为程序员,在选择将什么作为删除程序类型模板参数传递给我时,如何利用它
std::unique_ptr
?
通常,您无需担心。std::unique_ptr<T, D>
为要使用的删除器类型指定适当的名称:然后,任何A
可以适当地用于构造的明智类型D
将起作用,而任何不起作用的类型将不起作用。毕竟,这里的详细规范正在增加实现的复杂性,以降低用户的复杂性!
是std :: unique_ptr的构造函数被模板化的事实,为什么必须提供deleter模板参数?
从本质上讲,是的。解决因果关系的方法无关紧要。(可以将其模板化以强制执行“您可能不能将这些构造函数与CTAD一起使用”,或者可能必须对其进行模板化,从而导致“您可能不能将这些构造函数与CTAD一起使用”:最终没有关系。)
如果对上述问题的回答是肯定的,那么如果通过类模板自变量从链接页面的含义中选择了这两个构造函数中的任何一个,则该句子的格式将不正确?
那std::unique_ptr foo(value(), deleter());
是非法的,并且应该导致编译错误。这与CTAD的工作方式有关,如果您对此感兴趣,请参阅CTAD上的cppref文档以获得更好的主意。
_Dp和_Del实际上有何区别,这有何重要意义?
我们可以传递一个类型的对象A
,其中A
是与之不同的类型D
,但是可以用该对象构造一个类型的对象D
。而且,我们要转发这种类型:我们不需要不必要的副本。引用(适当时为lvalue或rvalue)A
允许我们直接D
在唯一指针中构造a 。这类似于.emplace
在标准容器中的用法。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句