为什么std :: map的move构造函数不是noexcept? [英] Why is std::map's move constructor not noexcept?

查看:98
本文介绍了为什么std :: map的move构造函数不是noexcept?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如cppreference.com所说,

As said by cppreference.com,

地图通常以红黑树的形式实现.

Maps are usually implemented as red-black trees.

因此移动std::map只是将指针移动到根node +其他信息(例如大小).为什么std::map的move构造函数未标记为noexcept?

So moving a std::map is just moving the pointer to the root node + other information such as size. Why is std::map's move constructor not marked as noexcept?

推荐答案

这是因为我无法将所有实现者都说成可以放入map的无资源状态.例如,即使在默认构造状态下,实现也需要有一个指向的终端节点.允许(但不是必需)将终端节点放在堆上的实现.

It is because I couldn't talk all of the implementors into a resource-less state that the map could be put into. For example an implementation needs to have an end-node to point to, even in the default-constructed state. Implementations are allowed, but not required, to put that end-node on the heap.

移出的地图必须处于有效状态.即从map移出的对象必须具有一个结束节点,以指向end()调用时.在进行移动构造之前,map中将存在一个要从其移动的末端节点.在移动构造之后,必须存在两个末端节点:一个在新的map中,一个在移动的`map中.

A moved-from map must be in a valid state. I.e. a moved-from map must have an end node to point to when end() gets called. Before the move construction, there exists one end node in the map that you're about to move from. After the move construction there must exist two end nodes: one in the new map and one in the moved-from `map.

如果末端节点进入堆,这意味着move构造函数不会转移末端节点的所有权,因此必须为新的`map分配一个新的末端节点.或确实转移了末端节点,但随后必须分配一个新节点,以留在移出的源中.

If the end node goes on the heap, that means that the move constructor either doesn't transfer ownership of the end node, and thus has to allocate a new end node for the new `map. Or does transfer the end node, but then has to allocate a new one to leave in the moved-from source.

如果将结束节点嵌入在map数据结构本身中,则永远不需要在堆上分配它.构造map时,它会自动分配在堆栈上".

If the end node is instead embedded within the map data structure itself, then it never need be allocated on the heap. It is automatically "allocated on the stack" as the map gets constructed.

如果需要,可以允许实现使map移动构造函数noexcept,只是不需要这样做.

Implementations are allowed to make the map move constructor noexcept if they want to, they just aren't required to.

这是默认构造函数的noexcept状态的调查,该构造函数的移动异常和移动赋值运算符容器是我几年前采用的实现方式.此调查假设每个容器为std::allocator.我只是对它进行了map检查,结果没有改变.

Here is a survey of the noexcept-state of the default constructor, move constructor and move assignment operator of the containers among the implementations that I took several years ago. This survey assumes std::allocator for each container. I just spot checked it for map and the results haven't changed.

如果您想自己进行此调查,请使用以下代码:

If you would like to run this survey yourself, here is the code:

#include "type_name.h"
#include <iostream>
#include <type_traits>

#include <deque>
#include <forward_list>
#include <list>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

template <class C>
void
report()
{
    using namespace std;
    const auto name = type_name<C>();
    if (is_nothrow_default_constructible<C>::value)
        std::cout << name << " is noexcept default constructible\n";
    else
        std::cout << name << " is NOT noexcept default constructible\n";
    if (is_nothrow_move_constructible<C>::value)
        std::cout << name << " is noexcept move constructible\n";
    else
        std::cout << name << " is NOT noexcept move constructible\n";
    if (is_nothrow_move_assignable<C>::value)
        std::cout << name << " is noexcept move assignable\n\n";
    else
        std::cout << name << " is NOT noexcept move assignable\n\n";
}

int
main()
{
    using namespace std;
    report<deque<int>>();
    report<forward_list<int>>();
    report<list<int>>();
    report<vector<int>>();
    report<string>();
    report<map<int, int>>();
    report<set<int>>();
    report<unordered_map<int, int>>();
    report<unordered_set<int>>();
}

其中"type_name.h"来自此答案.

这篇关于为什么std :: map的move构造函数不是noexcept?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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