例如,代替
void shared_ptr::reset() noexcept;
template <typename Y>
void shared_ptr::reset(Y* ptr);
有人可能会想到
template <typename Y = T>
void shared_ptr::reset(Y* ptr = nullptr);
我认为此处的性能差异可以忽略不计,第二个版本更为简洁。C ++标准采用第一种方法是否有任何特定原因?
在同样的问题已经被问了科特林语言,默认参数为首选那里。
更新:
std::unique_ptr::reset()
遵循默认参数设计(请参阅此处)。因此,我认为std::shared_ptr::reset()
使用重载的原因是因为它们具有不同的异常规范。
关键的区别在于,这两个操作实际上在语义上并不相同。
第一种是shared_ptr
没有管理对象的离开。第二个是让指针管理另一个对象。这是一个重要的区别。在单个函数中实现它意味着我们实质上将使一个函数执行两种不同的操作。
此外,每个操作可能对所讨论的类型具有不同的约束。如果将它们转储到一个函数中,则“两个分支”都必须满足相同的约束,而这是不必要的限制。C ++ 17并constexpr if
减轻它,但是这些功能是在退出之前指定的。
最终,我认为这种设计符合Scott Meyers的建议。如果默认参数使您在语义上有所不同,则可能是另一个重载。
好的,请修改一下。是的,例外规范不同。但是就像我之前提到的那样,它们之所以不同的原因是,这些函数在做不同的事情。成员的语义reset
要求:
void reset() noexcept;
效果:相当于
shared_ptr().swap(*this)
。template<class Y> void reset(Y* p);
效果:相当于
shared_ptr(p).swap(*this)
。
那里没有什么大新闻。每个函数都shared_ptr
具有使用给定参数(或缺少给定参数)构造新函数并进行交换的作用。那么,shared_ptr
构造函数做什么呢?根据上一节,他们执行以下操作:
constexpr shared_ptr() noexcept;
效果:构造一个空的shared_ptr对象。
后置条件:use_count() == 0 && get() == nullptr
。template<class Y> explicit shared_ptr(Y* p);
后置条件:
use_count() == 1 && get() == p
。当无法获取除内存以外的资源时抛出:bad_alloc
,或实现定义的异常
注意指针使用计数的不同发布条件。这意味着第二次超载需要考虑任何内部簿记。并且很可能为其分配存储。这两个重载的构造函数执行不同的操作,就像我之前说的那样,这是将它们分离为不同函数的有力提示。可以得到更强有力的例外保证的事实进一步证明了该设计选择的合理性。
最后,为什么unique_ptr
两个动作都只有一个过载?因为默认值不会更改语义。它只需要跟踪新的指针值。值是null的事实(无论是从默认参数还是其他值)都不会彻底改变函数的行为。因此会发出一个过载信号。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句