我有一张向量图:
std::map<int, std::vector<bool>> mymap
有时,我需要插入一个新元素:
auto& newvec = mymap[42];
// Add stuff to newvec
据我所知(并假设地图中还没有42),这将给我newvec
长度为0(构造为std::vector<bool> {}
),然后我可以对其进行扩展。
是否可以立即将向量初始化为某个大小n
?
(我不关心性能,只是想知道是否有办法做到这一点)。
答案 0 :(得分:4)
std::vector<bool>
您可以通过以下方式包装要初始化的std::vector<bool>
:
template<size_t N>
struct myvector {
myvector(): data(N) {}
std::vector<bool> data;
};
然后,将mymap
声明为其值类型属于这种包装类型myvector<N>
而不是std::vector<bool>
的映射。例如,对于N
等于100
:
std::map<int, myvector<100>> mymap;
如果键42
在地图中尚不存在,则:
auto& newvec = mymap[42];
将创建类型为myvector<100>
的实例,该实例依次初始化大小为std::vector<bool>
的{{1}}。
您可以通过100
的{{1}}数据成员或执行std::vector<bool>
来访问创建的myvector
对象。
data
和reinterpret_cast<std::vector<bool>&>(newvec)
另一种方法是使用std::map::find()
而不是std::map::emplace()
,通过将其返回的迭代器与std::map::find()
返回的迭代器进行比较,首先找出映射中是否存在给定的密钥。如果给定的键不存在,则使用std::map::operator[]()
构造向量。
在您的示例中,可以通过三元运算符来为此方法初始化std::map::end()
:
std::map::emplace()
实际上,您可以直接调用newvec
而无需检查给定密钥是否存在,但是如果密钥已经存在,这将花费无用的创建临时对象(即auto it = mymap.find(42); // search for an element with the key 42
bool is_key_in_map = it != mymap.end();
// if the element with the given key exists, then return it, otherwise
// construct it
auto& newvec = is_key_in_map? it->second:
mymap.emplace(42, std::vector<bool>(100, true)).first->second;
对象)的费用。在地图上显示:
std::map::emplace()
std::vector<bool>
您可以使用std::map::try_emplace()
代替auto& newvec = mymap.emplace(42, std::vector<bool>(100, true)).first->second;
:
std::map::try_emplace()
这样,如果地图已经包含给定的键(即如果它已经包含键std::map::emplace()
),则不会构造临时对象auto& newvec = mymap.try_emplace(42, 100, true).first->second;
。因此,这比使用std::vector<bool>(100, true)
更有效,因为如果不需要的话,不会构造临时对象。但是,它确实需要C ++ 17。
答案 1 :(得分:3)
您可以使用map::emplace成员函数:
mymap.emplace(42, std::vector<bool>(125, false));
为键std::vector<bool>(125, false)
创建一个42
值。
就像ネロク所提到的那样,即使键emplace
已经存在于地图中,上述std::vector<bool>(125, false)
调用也会构造值42
(这也记录在我上面链接的cppreference页中)。如果要避免这种情况,可以先使用map::find检查该值是否已存在,然后仅在键不存在时才插入该值。那就是:
if (mymap.find(42) == mymap.end()) {
mymap.emplace(42, std::vector<bool>(125, false));
}
map::find和map::emplace都具有对数时间复杂度;因此,在性能至关重要的情况下,在emplace之前调用find不会对性能造成太大影响。
答案 2 :(得分:2)
map::try_emplace()
(或在C ++ 17之前使用map::emplace()
)std::vector具有一个构造函数,该构造函数具有初始大小和初始统一值。在您的情况下,假设您希望初始大小为125。对于独立的载体,您将使用:
size_t num_bools_we_want = 1234;
std::vector<bool> my_vec(num_bools_we_want, false);
现在,std::map
有一个名为map::try_emplace()
的方法,该方法将参数转发到值类型的构造函数,这实际上使您可以选择将用于新元素的构造函数。这是使用方法
mymap.try_emplace(42, num_bools_we_want, false);
为键std::vector<bool>(num_bools_we_want, false)
创建值42
。没有创建临时向量(无论编译器如何优化)。
此解决方案的唯一“问题”是try_emplace()
仅在C ++ 17起存在。自从您询问C ++ 11以来,该版本的标准引入了map::emplace()
,除了复制密钥的问题外,它的功能几乎相同。有关emplace()
和try_emplace()
之间的区别的讨论,请参见this question。