std :: move_if_noexcept的理由仍然移动抛出只移动类型? [英] Rationale for std::move_if_noexcept still moving throwing move-only types?

查看:214
本文介绍了std :: move_if_noexcept的理由仍然移动抛出只移动类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

move_if_noexcept 将:




  • 返回一个右值 - 如果移动构造函数 noexcept

  • 返回左值 - 强制复制

  • 如果没有复制构造函数ul>

    我发现这个令人惊讶的是,只有move-ctor的移动类型仍然会使用 move_if_noexcept



    有没有给出一个彻底的理由? (可能直接或在 N2983 之间?)



    不会编译代码更好,不编译,而不是仍然面对不可恢复的移动场景?在N2983中给出的向量是很好的:

      void reserve n)
    {
    ... ...
    new((void *)(new_begin + i))value_type(std :: move_if_noexcept((* this)[i] ;
    }
    catch(...)
    {
    while(i> 0)//清除新元素
    (new_begin + --i) ;〜value_type();

    this-> deallocate(new_begin); // release storage
    throw;
    }
    *!* // --------不可逆变换从这里开始-----------
    this-> deallocate(this-> ;开始_ );
    this-> begin_ = new_begin;
    ... ...

    标记行中的注释实际上是错误的 - 对于可移动构建的移动类型,当我们将旧元素移动到新位置时,可能失败的不可逆变异已经开始。



    它简单地说,我会说一个抛出的移动类型不能放入向量否则,但也许不应该?

    解决方案


    简单地看一下,我会说,抛出的move-only类型不能
    被放入向量否则,但也许不应该?


    我相信你很好地总结了委员会对move-only-noexcept(false)类型的容器的选择。


    1. 允许他们使用基本的例外安全,而不是强制执行某些操作。

    2. 编译时间。

    A。委员会绝对认为他们不能默认地将现有的C ++ 03代码从具有强大的异常安全性改为具有基本的异常安全性。



    B。对于具有强异常安全性的那些函数,委员会更倾向于让那些成员继续具有强大的异常安全性,即使对于不可能被编写的代码(例如,用于操作仅移动类型的函数)。



    委员会意识到,它可以实现上述两个目标,除了B)中的移动类型可能在移动建设期间抛出的情况。这些情况限于向量的几个成员函数 IIRC: push_back reserve 。注意,向量的其他成员只提供了基本的异常安全性(即使在C ++ 98/03中),例如:赋值,插入(除非在结尾插入) 。



    考虑到这一点,委员会的决定是客户创建一个向量 -only-noexcept(false)-type,对客户端放松强大的异常安全性到基本(对于其他向量成员已经是这样)将更有用,而不是拒绝编译。



    这只是客户端为C ++ 11而不是旧代码编写的新代码,因为在C ++ 11之前不存在仅移动类型。毫无疑问,C ++ 11的教育者应该鼓励他们的学生写noexcept(true)移动成员。但是具有基本异常安全保障的代码不是那么危险,也不常见,所以应该禁止。毕竟,std :: lib已经充满了只包含基本异常安全保证的代码。


    move_if_noexcept will:

    • return an rvalue -- facilitating a move -- if the move constructor is noexcept or if there is no copy constructor (move-only type)
    • return an lvalue -- forcing a copy -- otherwise

    I found this rather surprising, as a move-only type that has a throwing move-ctor will still have this move-ctor invoked by code that uses move_if_noexcept.

    Has there been given a thorough rationale for this? (Maybe directly or between the lines of N2983?)

    Wouldn't code be better off not compiling rather than still having to face the unrecoverable move scenario? The vector example given in N2983 is nice:

    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;
            ... ...
    

    The comment given in the marked line is actually wrong - for move-only types that can throw on move construction, the - possibly failing - irreversible mutation actually already starts when we move the old elements into their new positions.

    Looking at it briefly, I'd say that a throwing move-only type couldn't be put into a vector otherwise, but maybe it shouldn't?

    解决方案

    Looking at it briefly, I'd say that a throwing move-only type couldn't be put into a vector otherwise, but maybe it shouldn't?

    I believe you've nicely summed up the choices the committee had for containers of move-only-noexcept(false)-types.

    1. Allow them but with basic exception safety instead of strong for some operations.
    2. Disallow them at compile time.

    A. The committee absolutely felt that they could not silently change existing C++03 code from having the strong exception safety to having basic exception safety.

    B. For those functions that have strong exception safety, the committee much preferred to have those members continue to have strong exception safety, even for code that could not possibly be written yet (e.g. for functions manipulating move-only types).

    The committee realized it could accomplish both of the objectives above, except for the case in B) where the move-only type might throw during move construction. These cases are limited to a few member functions of vector IIRC: push_back, reserve. Note that other members of vector already offer only basic exception safety (even in C++98/03), e.g.: assignment, insert (unless inserting at the end), erase.

    With all this in mind, it was the committee's decision that should the client create a vector of a move-only-noexcept(false)-type, it would be more useful to the client to relax the strong exception safety to basic (as it already is for other vector members), rather than to refuse to compile.

    This would only be new code that the client writes for C++11, not legacy code, since move-only types do not exist prior to C++11. And no doubt the educators of C++11 should be encouraging their students to write noexcept(true) move members. However code with the basic exception safety guarantee is not so dangerous, nor unusual, such that it should be forbidden. After all, the std::lib is already chock full of code carrying only the basic exception safety guarantee.

    这篇关于std :: move_if_noexcept的理由仍然移动抛出只移动类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆