在下面的程序中,我將一些信息存儲在哈希表(std :: unordered_map)中,關鍵是類RectData的一個對象,關聯的值是一個元組uint,RectData,枚舉>和自定義KeyHash和KeyEqual已被定義。爲什麼使用unordered_map和tuple需要默認構造函數?
插入一個<鍵值>對沒有默認的構造函數給出了gcc 4.9.2的兩頁錯誤。第一個錯誤的行是:
visited_info[rect0] = info0;
我再次檢查與MSVC++ 12.0,我也有錯誤消息。
當我添加默認構造函數時,編譯是可以的,並且在運行時調用默認構造函數。我無法理解爲什麼RectData類需要默認構造函數?
使用[]運算符從哈希表中檢索數據也需要編譯時的默認構造函數,但它在運行時不會被調用,爲什麼?
auto info = visited_info[rect];
注:與visited_info.emplace()和visited_info.find()改變代碼解決了這個問題,但沒有回答這個問題。
感謝您的回答。
完整代碼如下。
#include <boost/functional/hash.hpp>
#include <tuple>
#include <vector>
#include <unordered_map>
#include <iostream>
using uint = unsigned int;
enum class Direction : int { left = 0, right = 1, up = 2, down = 3, null = 4 };
class RectData {
public:
RectData(uint width, uint height)
: width_(width), height_(height), datas_(width * height, 0) {
total_ = width_ * height_;
}
// A default constructor must be defined!
RectData() : RectData(0u, 0u) {
std::cout << "Calling the default constructor !!!" << std::endl;
}
size_t hash() const {
return boost::hash_value(datas_);
}
bool operator==(const RectData &rect) const {
return (width_ == rect.width_) &&
(height_ == rect.height_) &&
(datas_ == rect.datas_);
}
struct KeyHash {
std::size_t operator()(const RectData &rect) const {
return rect.hash();
}
};
struct KeyEqual {
std::size_t operator()(const RectData &r1, const RectData &r2) const {
return r1 == r2;
}
};
private:
uint width_;
uint height_;
std::vector<uint> datas_;
uint total_;
};
using StoredInfo = std::tuple<uint, RectData, Direction>;
int main() {
std::unordered_map<RectData, StoredInfo, RectData::KeyHash,
RectData::KeyEqual> visited_info;
RectData rect0(5u, 5u);
RectData rect1(4u, 4u);
RectData rect2(3u, 3u);
RectData rect3(2u, 2u);
StoredInfo info0 = std::make_tuple(10u, rect1, Direction::up);
StoredInfo info1 = std::make_tuple(11u, rect2, Direction::down);
StoredInfo info2 = std::make_tuple(12u, rect3, Direction::left);
StoredInfo info3 = std::make_tuple(13u, rect0, Direction::right);
// the line below requires a default RectData constructor!!!
visited_info[rect0] = info0;
// default RectData constructor also needed here !!!
visited_info[rect1] = std::move(info2);
// but not needed here
visited_info.insert(std::make_pair(rect2, info2));
// and not needed here
visited_info.emplace(rect3, info3);
// but needed here and not called!!!
StoredInfo i1 = visited_info[rect1];
std::cout << "Verify (must be 11) = " << std::get<0>(i1)
<< std::endl;
// but needed here and not called!!!
StoredInfo &i2 = visited_info[rect2];
std::cout << "Verify (must be 12) = " << std::get<0>(i2)
<< std::endl;
// and not needed here
auto it = visited_info.find(rect3);
std::cout << "Verify (must be 13) = " << std::get<0>(it->second)
<< std::endl;
}
在'visited_info [rect0] = info0;'中,首先調用'operator []',它別無選擇,只能默認構造一個新元素並返回一個引用。然後在該新元素上調用'operator ='。與'auto info = visited_info [rect];' - 'operator []'一樣,需要一個默認構造函數,以防給定鍵的條目不存在。如果條目確實存在,則返回對現有元素的引用,並且不調用默認構造函數。 –
[Using std :: map where V has no default default constructor](http:// stackoverflow。com/questions/1935139/using-stdmapk -v-where-v-has-no-useful-default-constructor) –
瞭解了,謝謝你對operator []的默認構造的明確解釋。 – user3636086