[英]How to make a C++ map container where the key is part of the value?
我想存儲一堆鍵值對象,但是值對象本身(和對它的引用)知道它的鍵。 我還想有效地查找僅給定鍵的這些對象。
class SomeObject
{
private:
//String or integer. int seem cheap enough to duplicate with std::map, but
//strings seem pretty expensive when there may be thousands of objects in existence.
//Reference/Pointer to key is fine
const SomeOtherObject key;
...other stuff...
public:
...methods, some of which use the key in some way...
};
C++14 std::set::find
非鍵搜索
如http://en.cppreference.com/w/cpp/container/set/find所述,C++14 添加了兩個新的find
API:
主程序
template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;
這允許您執行以下操作:
主程序
#include <cassert>
#include <set>
class Point {
public:
// Note that there is _no_ conversion constructor,
// everything is done at the template level without
// intermediate object creation.
//Point(int x) : x(x) {}
Point(int x, int y) : x(x), y(y) {}
int x;
int y;
};
bool operator<(const Point& c, int x) { return c.x < x; }
bool operator<(int x, const Point& c) { return x < c.x; }
bool operator<(const Point& c, const Point& d) {
return c.x < d;
}
int main() {
// std::less<> because of:
// https://stackoverflow.com/questions/20317413/what-are-transparent-comparators
std::set<Point, std::less<>> s;
s.insert(Point(1, -1));
s.insert(Point(2, -2));
s.insert(Point(0, 0));
s.insert(Point(3, -3));
assert(s.find(0)->y == 0);
assert(s.find(1)->y == -1);
assert(s.find(2)->y == -2);
assert(s.find(3)->y == -3);
// Ignore 1234, find 1.
assert(s.find(Point(1, 1234))->y == -1);
}
在 Ubuntu 16.10、 g++
6.2.0 上測試,使用:
g++ -std=c++14 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
使用自定義類而不是less<>
這使事情更加明確,並允許您為每個類編寫多個比較器:
#include <cassert>
#include <set>
class Point {
public:
Point(int x, int y) : x(x), y(y) {}
int x;
int y;
};
struct PointCmpY {
// https://stackoverflow.com/questions/20317413/what-are-transparent-comparators
typedef std::true_type is_transparent;
bool operator()(const Point& lhs, int rhs) const {
return lhs.y < rhs;
}
bool operator()(int lhs, const Point& rhs) const {
return lhs < rhs.y;
}
bool operator()(const Point& lhs, const Point& rhs) const {
return lhs.y < rhs.y;
}
};
int main() {
std::set<Point, PointCmpY> s;
s.insert(Point(1, -1));
s.insert(Point(2, -2));
s.insert(Point(0, 0));
s.insert(Point(3, -3));
assert(s.find(0)->x == 0);
assert(s.find(-1)->x == 1);
assert(s.find(-2)->x == 2);
assert(s.find(-3)->x == 3);
assert(s.find(Point(1234, -1))->x == 1);
}
也可以看看
我感覺到你的痛苦。 讓我生氣的是set
和map
總是使用相同的數據結構在引擎蓋下實現,這是一個用鍵提取器參數化的值tree
。 不幸的是,標准中沒有這樣的東西。
如果 boost 沒問題,請使用Boost.MultiIndex來實現您的需求。 也看看Boost.Intrusive 。
C++ 提供了mutable
關鍵字,允許您使用第二種解決方案—— set
。 在您的項目類中將您的值聲明為mutable
將允許修改它,即使該項目是const
。 另請參閱:除了允許 const 函數修改變量之外,“mutable”關鍵字還有其他用途嗎?
或者,更簡單的是,為您的值實現一個訪問器, const_cast
遠離項目的常量性。
...但是值對象本身(和對它的引用)知道它的鍵
地圖:
對象無法知道“它的”鍵,因為指向同一個對象的指針可能會被添加到多個映射中,使用不同的鍵。 密鑰屬於地圖; 不是對象。
放:
當這個成員的值發生變化時會發生什么? 您將如何強制重新索引? 這就是 set 強制執行常量的原因。
——
您正在嘗試根據其成員之一對給定類的項目進行索引,但您不想復制此成員用於索引目的,並且您不想使對象成為 const(我假設您確實想要使成員為 const)。
我會在紅黑樹或 AVL 樹上構建它。
我對 ybungalobill 建議的 Boost.MultiIndex 不夠熟悉。 我不確定它的實例化代碼是否復制了索引成員,或者它如何處理該成員的值更改。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.