C ++:如何在地图中以非零大小初始化矢量

时间:2018-11-17 11:06:05

标签: c++ c++11 stl

我有一张向量图:

std::map<int, std::vector<bool>> mymap

有时,我需要插入一个新元素:

auto& newvec = mymap[42];
// Add stuff to newvec

据我所知(并假设地图中还没有42),这将给我newvec长度为0(构造为std::vector<bool> {}),然后我可以对其进行扩展。

是否可以立即将向量初始化为某个大小n

(我不关心性能,只是想知道是否有办法做到这一点)。

3 个答案:

答案 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对象。


使用datareinterpret_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()

自C ++ 17起: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::findmap::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