提问人:Zebrafish 提问时间:9/23/2023 最后编辑:Jan SchultkeZebrafish 更新时间:9/23/2023 访问量:107
为什么 std::unordered_map 中的 emplace 方法采用多个参数?
Why does the emplace method in std::unordered_map take multiple parameters?
问:
这对我来说是一个困惑的根源,但是 std::unordered_map::try_emplace 为 value(mapped) 类型的构造函数获取键和变量参数,但是 ::emplace 应该采用 std::p air<key, value>:
此外,try_emplace 将键和参数处理为 mapped_type单独,不像 emplace,它需要参数 构造value_type(即 std::p air)。
好吧,这很令人困惑。为什么函数签名是:
template< class... Args >
std::pair<iterator, bool> emplace( Args&&... args );
如上所述,如果需要构造 std::p air<key, value>为什么还要有多个参数?
答:
通常,这是因为它实际上旨在将参数转发到对象的构造函数。
(它可以是复制构造函数,在这种情况下,您只使用一个参数和值(或要存储的 r-value0,但不需要)。emplace
在这个特定的例子中,它的值是,所以它不太有用。std::pair
例:
#include<unordered_map>
int main() {
std::unordered_map<int, double> m;
m.emplace(42, 3.14); // the constructor of pair will be called with these two parameters.
}
https://godbolt.org/z/PYx51jT4x
有些人不建议对某些容器使用 emplace,因为确实没有太多的收益,并且可能会产生误导,因为很多时候,在知道需要“在哪里”之前,无论如何都会构造值,然后复制到那里,而不是真正放置。
看看 Meyer 的书,“有效的现代 C++:改进 C++11 和 C++ 使用的 42 种具体方法”
现在不确定是否是其中之一。unordered_set
评论
pair
emplace
std::pair
emplace
std::unordered_map::emplace
完美地将所有参数转发给 的构造函数,因此就好像您调用了:std::pair
// value_type is defined as std::pair<...> for a std::unordered_map
value_type(std::forward<Args>(args...)
通常,将所有参数转发到标准库容器。.emplace
value_type
对于 ,这开辟了无数的可能性,因为现在您可以:std::unordered_map
- 调用一元构造函数,如
.emplace(std::pair{key, value})
- 调用二进制构造函数,例如
.emplace(key, value)
- 调用其他构造函数,例如
.emplace(std::piecewise_construct, std::forward_as_tuple(key_args...), std::forward_as_tuple(value_args...))
std::unordered_map::try_emplace
是不同的,因为它构造了一个与值分开的键。如果密钥尚不存在,它只会构造存储在映射中的完整内容。显然,它不能简单地将所有参数转储到 a 中,并且需要一些分离。std::pair
std::pair
注意:对于大多数意图和目的,try_emplace
优先于放置
。另请参阅此答案。
注意:这里所说的一切都同样适用于 std::map
。
对于所有容器,都接受参数并将它们转发给 的构造函数,该构造函数是 的键和映射类型。emplace
value_type
std::pair
const
std::unordered_map
std::pair
具有接受 0、1、2 和 3 参数的构造函数。所以应该支持所有这些。的确,没有构造函数允许在标准库中指定超过 3 个参数,但指定此特定参数最多只接受 3 个参数不会有太大好处。emplace
std::pair
emplace
此外,允许用户专用于自己的类型(只要它满足标准库要求),并且可以添加一个接受 3 个以上参数的构造函数。在这种情况下,不应不必要地不相容。std::pair
emplace
下面是一个示例,其中将元素插入到映射中的唯一可能方法是使用三个参数 ,因为键类型是不可移动的,使用其构造函数可以避免键或映射类型的所有副本/移动。emplace
std::piecewise_construct
std::pair
struct Key {
int i;
Key(int i) : i(i) {}
Key(const Key&) = delete;
Key& operator=(const Key&) = delete;
bool operator==(const Key&) const = default;
};
constexpr auto hash = [](const Key& k){ return k.i; };
int main() {
std::unordered_map<Key, int, decltype(hash)> m;
m.emplace(std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(1));
}
评论
emplace
Container::value_type
std::pair
std::piecewise_construct
try_emplace
emplace