簡體   English   中英

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

[英]C++: how to initialize vector in map with non-zero size

我有一個矢量地圖:

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

有時,我需要插入一個新元素:

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

據我所知(並假設42還沒有在地圖中),這將給我newvec長度為0(構造為std::vector<bool> {} )然后我可以擴展。

有沒有辦法立即將矢量初始化為某個大小的n

(我不關心性能,只是想知道是否有辦法做到這一點)。

包裝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>類型的實例,它myvector<100>初始化一個大小為100std::vector<bool>

您可以通過myvectordata數據成員或執行reinterpret_cast<std::vector<bool>&>(newvec)來訪問創建的std::vector<bool>對象。


使用std::map::find()std::map::emplace()

另一種方法是使用std::map::find()而不是std::map::operator[]()來首先通過比較返回的迭代器和返回的迭代器來確定給定的鍵是否已經存在於映射中by std::map::end() 如果給定的鍵不存在,則使用std::map::emplace()構造向量。

在您的例子中, newvec可以初始化本辦法由三元opererator方式:

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>對象)。密鑰已存在於地圖中:

auto& newvec = mymap.emplace(42, std::vector<bool>(100, true)).first->second;

從C ++ 17開始: std::map::try_emplace()

您可以使用std::map::try_emplace()而不是std::map::emplace()

auto& newvec = mymap.try_emplace(42, 100, true).first->second;

這樣,如果映射已經包含給定鍵(即,如果它已經包含鍵42 ),則不會構造臨時對象std::vector<bool>(100, true) )。 因此,這比使用std::map::emplace()更有效,因為如果沒有必要,不會構造臨時對象。 但是,它確實需要C ++ 17。

你可以使用map :: emplace成員函數:

mymap.emplace(42, std::vector<bool>(125, false));

為密鑰42創建std::vector<bool>(125, false)值。

正如ネロク提到的,上面的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都具有對數時間復雜度; 因此,在安撫之前調用查找不應該在性能關鍵場景中過多地損害性能。

使用map::try_emplace()map::emplace()之前C ++ 17)

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);

為密鑰42創建std::vector<bool>(num_bools_we_want, false)值。 不會創建臨時向量(無論編譯器優化如何)。

這個解決方案唯一的“問題”是try_emplace()僅在C ++ 17之后才存在。 既然你問過C ++ 11 - 那個版本的標准引入了map::emplace() ,除了制作密鑰副本的問題外幾乎完全相同。 這個問題的差別之間的討論emplace()try_emplace()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM