【发布时间】:2018-04-10 13:10:14
【问题描述】:
如何将空向量放入std::map?例如,如果我有一个std::map<int, std::vector<int>>,并且我希望map[4] 包含一个空的std::vector<int>,我可以调用什么?
【问题讨论】:
-
map[4]是否存在? -
看起来像 XY 问题,为什么需要一个空向量?
如何将空向量放入std::map?例如,如果我有一个std::map<int, std::vector<int>>,并且我希望map[4] 包含一个空的std::vector<int>,我可以调用什么?
【问题讨论】:
map[4] 是否存在?
如果您使用operator[](const Key&),如果您使用了访问不存在的元素。见这里:
http://en.cppreference.com/w/cpp/container/map/operator_at
(从 C++ 11 开始,细节有点复杂,但在你的情况下,这才是最重要的)。
这意味着如果您的地图为空并且您执行map[4],它会很容易地为您提供对空(默认构造)向量的引用。分配一个空向量是不必要的,尽管它可能会让你的意图更清楚。
【讨论】:
不幸的是,严格正确的答案确实是使用std::piecewise_construct 作为第一个参数,然后是两个元组。第一个表示创建键 (4) 的参数,第二个表示创建向量的参数(空参数集)。
看起来像这样:
map.emplace(std::piecewise_construct, // signal piecewise construction
std::make_tuple(4), // key constructed from int(4)
std::make_tuple()); // value is default constructed
当然这看起来难看,其他替代方案也可以。他们甚至可能在优化的构建中不再生成代码:
这个概念上调用了默认构造和移动赋值,但优化器很可能会看穿它。
map.emplace(4, std::vector<int>());
这调用了默认构造,然后是复制分配。但同样,优化器很可能会看穿它。
map[4] = {};
【讨论】:
emplace 时,OP 并没有意识到他们在做什么。后面的句子揭示了他们实际上试图解决的问题。也就是说,如果 OP 真的意味着我们应该只使用 emplace,那么我同意这个答案是“严格正确的”。
为确保将空向量放置在位置 4,您可以简单地尝试 clear 位置 4 的向量。
std::map<int, std::vector<int>> my_map;
my_map[4].clear();
正如其他人所提到的,std::map 的索引运算符将在指定索引处构造一个空值(如果不存在)。如果是这种情况,调用clear 是多余的。但是,如果 std::vector<int> 确实存在,则对 clear 的调用用于清除那里的向量,从而产生一个空向量。
这可能比我之前分配给{} 的方法更有效(见下文),因为我们可能计划在位置 4 处向向量添加元素,并且我们不支付任何新分配的成本这种方式.此外,如果以前使用 my_map[4] 表示将来使用,那么我们的新向量最终可能会调整到与以前几乎相同的大小,这意味着我们可以节省重新分配成本。
只需分配给{},容器就应该在那里正确地构造一个空向量:
std::map<int, std::vector<int>> my_map;
my_map[4] = {};
std::cout << my_map.size() << std::endl; // prints 1
编辑:正如 Jodocus 所提到的,如果您知道 std::map 在位置 4 处尚未包含 vector,那么只需尝试访问该位置的向量将默认构造一个,例如:
std::map<int, std::vector<int>> my_map;
my_map[4]; // default-constructs a vector there
【讨论】:
my_map[4];就足够了。
my_map[4].clear(); 而不是分配。
最简单的解决方案有什么问题? std::map[4] = {};.
在现代 C++ 中,这应该可以满足您的需求,而无需或至少非常少的开销。
如果你必须使用emplace,我能想到的最佳解决方案是:
std::map<int, std::vector<int>> map;
map.emplace(4, std::vector<int>());
【讨论】:
map[4]; 没有分配
将分段构造与 std::make_tuple 一起使用:
map.emplace(std::piecewise_construct, std::make_tuple(4), std::make_tuple());
我们在位置 4 插入一个空向量。
如果有一般情况,例如,放置一个大小为 100 的向量,然后填充 10:
map.emplace(std::piecewise_construct, std::make_tuple(4), std::make_tuple(100, 10));
piecewise_construct:这个常量值作为第一个参数传递来构造一个pair对象,通过将两个元组对象的元素转发给它们各自的构造函数来选择构造其成员的构造函数形式。
【讨论】:
std::make_tuple 更改为std::make_tuple(),那么您的代码实际上会解决OP 提出的问题。