std::move_if_noexcept为什么会移动抛出异常的移动唯一类型?

8

move_if_noexcept将:

  • 如果移动构造函数是noexcept或者没有复制构造函数(仅具有移动构造函数),则返回一个右值,以便进行移动。
  • 否则,将返回一个左值,以强制执行复制操作。

我认为这相当令人惊讶,因为一个具有抛出异常移动构造函数的仅移动类型仍然会被使用move_if_noexcept的代码调用。

是否已经对此进行了彻底的解释?(也许在N2983中直接或间接给出了解释?)

与其面对不可恢复的移动情况,代码不编译岂不更好?在N2983中提供的vector示例很好:

void reserve(size_type n)
{
  ... ...
                 new ((void*)(new_begin + i)) value_type( std::move_if_noexcept( (*this)[i]) ) );
        }
        catch(...)
        {
            while (i > 0)                 // clean up new elements
               (new_begin + --i)->~value_type();

            this->deallocate( new_begin );    // release storage
            throw;
        }
*!*     // -------- irreversible mutation starts here -----------
        this->deallocate( this->begin_ );
        this->begin_ = new_begin;
        ... ...

标记行中给出的评论实际上是错误的-对于那些可以在移动构造时抛出异常的仅可移动类型,可能会失败的不可逆变异实际上已经在我们将旧元素移动到它们的新位置时开始了。

简单地看,我认为一个抛出异常的仅可移动类型否则不能放入向量中,但也许不应该这样做?


2010年的一个代码片段:“……过于保守的nothrow_xxx实现可能会对像unique_ptr这样具有非抛出移动操作的类型评估为false……”(来源:http://cpp-next.com/archive/2009/10/exceptionally-moving/comment-page-1/#comment-240) - Martin Ba
2
在向量修改程序中(不是erase,而是例如insert),有一个专门针对move-only类型的特殊段落:“如果非CopyInsertable类型的T的移动构造函数引发异常,则效果未指定。” 此外,请注意noexcept(false)不能保证函数不抛出异常。 - dyp
1个回答

7
简单来看,我认为一个仅具有移动语义的类型不能放入vector中,但也许不应该这样做?
我相信您已经很好地总结了委员会在容器移动语义和异常安全性方面的选择:
1.允许它们,但对一些操作只提供基本的异常安全性,而不是强的异常安全性。 2.在编译时禁止它们。
A. 委员会绝对认为他们不能在不强制要求的情况下改变现有的C++03代码,从而使其从强异常安全性变为基本异常安全性。
B. 对于那些具有强异常安全性的函数,委员会更喜欢那些成员继续具有强异常安全性,即使是对于可能无法编写的代码(例如,用于操纵仅可移动类型的函数)。
委员会意识到可以实现上述两个目标,除非在B)中,移动构造期间可能发生移动仅类型抛出的情况。这些情况仅限于vector的几个成员函数:push_back,reserve。请注意,vector的其他成员在C++98 / 03中已经仅提供基本异常安全性,例如:赋值,插入(除非插入在末尾),删除等。
考虑到所有这些,委员会决定,如果客户端创建一个移动仅noexcept(false)类型的vector,则将强异常安全性放松为基本异常安全性(就像其他vector成员一样)对于客户端更有用,而不是拒绝编译。
这只适用于客户端为C++11编写的新代码,而不是遗留代码,因为在C++11之前不存在移动仅类型。毫无疑问,C++11的教育者应该鼓励他们的学生编写noexcept(true)移动成员。但是,具有基本异常安全性保证的代码并不那么危险或不寻常,以至于应该被禁止。毕竟,std::lib已经充斥着只提供基本异常安全性保证的代码。

3
谢谢。我想知道,是否有任何常见框架中实际使用的合法move-only-noexcept(false)类型?从移动操作中抛出异常似乎甚至比从析构函数中抛出异常更没有意义(后者至少有其用途)。 - Martin Ba

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