Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么不';t容器移动分配运算符不例外?_C++_C++11 - Fatal编程技术网

C++ 为什么不';t容器移动分配运算符不例外?

C++ 为什么不';t容器移动分配运算符不例外?,c++,c++11,C++,C++11,我注意到std::string(实际上std::basic_string)的移动赋值运算符是noexcept。这对我来说是有道理的。但随后我注意到,没有一个标准容器(例如,std::vector,std::deque,std::list,std::map)声明其移动分配操作符noexcept)。这对我来说没什么意义。例如,std::vector,通常实现为三个指针,指针当然可以在不引发异常的情况下进行移动分配。然后我想可能问题在于移动容器的分配器,但是std::string也有分配器,所以如果这

我注意到
std::string
(实际上
std::basic_string
)的移动赋值运算符是
noexcept
。这对我来说是有道理的。但随后我注意到,没有一个标准容器(例如,
std::vector
std::deque
std::list
std::map
)声明其移动分配操作符
noexcept
)。这对我来说没什么意义。例如,
std::vector
,通常实现为三个指针,指针当然可以在不引发异常的情况下进行移动分配。然后我想可能问题在于移动容器的分配器,但是
std::string
也有分配器,所以如果这是问题所在,我希望它会影响
std::string


那么为什么
std::string
的移动分配操作符
noexcept
,而标准容器的移动分配操作符却不是呢?

我认为其原因是这样的

basic_string
仅适用于非数组POD类型。因此,它们的析构函数必须是微不足道的。这意味着,如果您对move赋值执行
交换
,则moved to字符串的原始内容尚未销毁对您来说并不重要

<> p>容器(Basic SythStudio在技术上不是C++的容器)可以包含任意类型。具有析构函数的类型,或包含具有析构函数的对象的类型。这意味着,对于用户来说,更重要的是保持对对象何时被销毁的精确控制。它特别指出:

a[移动到对象]的所有现有元素要么被指定移动,要么被销毁


因此,这种差异是有意义的。一旦开始释放内存(通过分配器),就不能进行移动分配
noexcept
,因为这可能会通过异常失败。因此,一旦您开始要求在move assign上释放内存,您就无法强制执行
noexcept

我相信我们看到的是标准缺陷。如果要将
noexcept
规范应用于移动分配操作符,则该规范有点复杂。我相信无论我们谈论的是
basic\u string
还是
vector
,这句话都是正确的

根据[container.requirements.general]/p7,我对集装箱移动分配操作员应该做的工作的英文翻译是:

C& operator=(C&& c)
如果
alloc\u traits::propagate\u on\u container\u move\u assignment::value
true
、转储资源、移动分配程序和传输 来自
c
的资源

如果
alloc\u traits::在容器上传播\u移动\u赋值::value
false
get_allocator()==c.get_allocator()
,转储资源和传输 来自
c
的资源

如果
alloc\u traits::在容器上传播\u移动\u赋值::value
false
get_分配器()!=c、 get_allocator()
,move分配每个
c[i]

注:

  • alloc\u traits
    指的是
    alloctor\u traits


    这项调查已经进行了大约一年,但据我所知仍然有效。

    容器类中的移动分配操作符被定义为无异常,因为许多容器都是为实现强异常安全保证而设计的。容器实现了强大的异常安全保证,因为在有移动分配操作符之前,必须复制容器。如果副本出现任何问题,新存储将被删除,容器将保持不变。现在我们被这种行为困住了。如果移动任务OP不在,则调用较慢的复制赋值操作符。

    你到底在哪里看到这个?@ C++标准中的洛基斯塔里。OP在问为什么它不是
    noexcept
    @nicolasbolas idiot me:),我反过来问了关于运算符=for string&。按标准,基本字符串不是容器。基本字符串的运算符=实际上并不例外<代码>效果:如果*this和str不是同一个对象,则修改*this,如表71所示。[注意:有效的实现是交换(str)。-结束注意]
    解除分配永远不会失败。如果释放资源可能会出现异常,那么几乎不可能编写容错C++代码。取消分配也发生在容器自己的析构函数(也将调用用户定义类型的析构函数)中,但C++11中的析构函数默认为
    noexcept
    ,这是有充分理由的。@AdamH.Peterson:析构函数默认为noexcept,但分配器不是。值得注意的是,.@nicolas,这可能是真的,但是标准库的容器的析构函数是
    noexcept
    ,这些析构函数调用分配器上的释放。如果分配器的释放函数失败,您最终会看到程序因noexcept冲突而中止。这对我来说意味着
    move()
    的原因可能不是
    noexcept
    与解除分配失败无关。为什么它应该应用于
    basic_string
    ?@nicolas:[container.requirements.general]/p13:本条款和(21.4)中定义的所有容器如表99所述,数组满足分配器感知容器的附加要求。如果总是相等,则可以通过使用
    来改善条件(C++17)。顺便说一句,您可能想使用分配器特性专门化,而不是原始分配器类型。
    
    C& operator=(C&& c)
            noexcept(
                 alloc_traits::propagate_on_container_move_assignment::value &&
                 is_nothrow_move_assignable<allocator_type>::value);
    
    C& operator=(C&& c)
            noexcept(
                 alloc_traits::propagate_on_container_move_assignment{} ||
                 alloc_traits::is_always_equal{});