例如,而不是
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++ 标准采用第一种方式有什么具体原因吗?
same question已被要求使用 Kotlin 语言,并且首选默认参数。
更新:
std::unique_ptr::reset()
遵循默认参数设计(参见 here )。所以我认为 std::shared_ptr::reset()
使用重载的原因是因为它们有不同的异常规范。
最佳答案
关键的区别在于,这两个操作实际上在语义上并不相同。
第一个意思是离开 shared_ptr
没有托管对象。第二个是让指针管理 another 对象。这是一个重要的区别。在单个函数中实现它意味着我们将基本上让一个函数执行两种不同的操作。
此外,每个操作可能对所讨论的类型有不同的限制。如果我们将它们转储到一个函数中,那么“两个分支”将必须满足相同的约束,这是不必要的限制。 C++17 和 constexpr if
缓解了它,但这些函数是在退出之前指定的。
最终,我认为这个设计符合 Scott Meyers 的建议。如果默认参数让你做一些语义不同的事情,它可能应该是另一个重载。
好的,现在来解决您的编辑问题。是的,异常(exception)规范不同。但就像我之前提到的那样,它们可能不同的原因是函数在做不同的事情。 semantics of the reset
members需要这个:
void reset() noexcept;
Effects: Equivalent to
shared_ptr().swap(*this)
.template<class Y> void reset(Y* p);
Effects: Equivalent to
shared_ptr(p).swap(*this)
.
那里没有什么大新闻。每个函数都具有使用给定参数(或缺少参数)构造一个新的 shared_ptr
并交换的效果。那么 shared_ptr
构造函数是做什么的呢?根据a preceding section ,他们这样做:
constexpr shared_ptr() noexcept;
Effects: Constructs an empty shared_ptr object.
Postconditions:use_count() == 0 && get() == nullptr
.template<class Y> explicit shared_ptr(Y* p);
Postconditions:
use_count() == 1 && get() == p
. Throws:bad_alloc
, or an implementation-defined exception when a resource other than memory could not be obtained
注意指针使用计数的不同后置条件。这意味着第二个重载需要考虑任何内部簿记。并且很可能会为它分配存储空间。这两个重载的构造函数做不同的事情,就像我之前所说的,这是将它们分成不同函数的强烈提示。能够获得更强的异常保证这一事实进一步证明了该设计选择的合理性。
最后,为什么 unique_ptr
两个 Action 都只有一个重载?因为默认值不会改变语义。它只需要跟踪新的指针值。 value 为 null 的事实(来自默认参数或其他)不会彻底改变函数的行为。因此,单个过载是合理的。
关于c++ - C++中的默认参数与重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48849887/