std::unique_ptr的“不抛出异常解引用”

7

我使用C++编写代码,其中使用了std::unique_ptr u来处理std::string资源,我想解引用u,以便将std::string传递给调用std::string复制构造函数的函数:

std::string* copy = new std::string( /*dereference u here*/ );

我知道newstd::string复制构造函数可能会抛出异常,但这不是我的重点。我只是想知道是否对u进行解引用操作就已经可以抛出异常。我觉得很奇怪operator*没有标记为noexcept,而std::unique_ptr方法get实际上被标记为noexcept。换句话说:
*( u.get() )

作为整体而言,noexcept 是指在运行时不会抛出异常。
*u

这是不是一个标准中的缺陷?我不明白为什么会有差异。有任何想法吗?


1
*(u.get())怎么可能是noexcept的呢?难道u.get()不可能返回nullptr吗? - BartoszKP
1
@BartoszKP,返回nullptrnoexcept有什么关系? - Slava
@BartoszKP:嗯,cplusplus.com上的参考文献说get是noexcept的……据我所知,解引用nullptr不会抛出异常。无论如何,在我尝试解引用之前,我都会检查if(u)。 - sperber
@Slava 是的,你说得对。我的意思是 operator* 可以验证您是否正在取消引用空指针,并在是的情况下抛出异常,而 get() 不应该这样做。但是,这仍然没有意义,因为 operator->noexcept... - BartoszKP
@Slava 在这里(http://en.cppreference.com/w/cpp/memory/unique_ptr/operator*)上说它可能会抛出异常。 - BartoszKP
显示剩余2条评论
1个回答

9
unique_ptr::operator*()可能涉及调用存储在unique_ptr中的类型的operator*()重载。请注意,存储在unique_ptr中的类型不一定是裸指针,您可以通过嵌套类型D::pointer更改类型,其中Dunique_ptr的删除器类型。这就是为什么该函数不是noexcept的原因。

但是,对于您存储std::string *而不是某些重载operator*的类型在unique_ptr中的用例,不适用此警告。因此,对于您来说,该调用实际上是noexcept的。


可以标记为 noexcept(noexcept(*std::declval<T>())) 吗? - Ryan Haining
@RyanHaining,这可能适用于我描述的边缘情况,但如果T是一个指针呢?现在你在noexcept规范中有一个nullptr解引用。 - Praetorian
@RyanHaining nullptr解引用部分是关于在修改注释为declval之前,当您正在对指针进行值初始化时的情况,我不确定即使在未评估的上下文中这样做是否可以。假设您noexcept规范中的T来自unique_ptr<T>,那么您可能正在尝试推迟重载operator*的类型的引用。如果T = unique_ptr<U>::pointer,其中假设为U*,那么您正在检查该类型是否具有noexcept构造函数(我想)。那个noexcept规范并不能在所有情况下实现您想要的效果。 - Praetorian
哦,是的,我现在看到我的错误了。 - Ryan Haining
2
此外,不将 operator * 设为 noexcept 可以使实现在调试模式下通过抛出异常来诊断 UB(如果存储的指针为空)。 - T.C.
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接