[英]How to make a C++ map container where the key is part of the value?
I want to store a bunch of key-value objects, but where the value object itself (and references to it) knows its key.我想存储一堆键值对象,但是值对象本身(和对它的引用)知道它的键。 I also want to efficiently lookup these objects given only the key.我还想有效地查找仅给定键的这些对象。
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
non-key searches C++14 std::set::find
非键搜索
As mentioned at http://en.cppreference.com/w/cpp/container/set/find C++14 has added two new find
APIs:如http://en.cppreference.com/w/cpp/container/set/find所述,C++14 添加了两个新的find
API:
main.cpp主程序
template< class K > iterator find( const K& x );
template< class K > const_iterator find( const K& x ) const;
which allow you to do:这允许您执行以下操作:
main.cpp主程序
#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);
}
Tested on Ubuntu 16.10, g++
6.2.0, with:在 Ubuntu 16.10、 g++
6.2.0 上测试,使用:
g++ -std=c++14 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Using a custom class instead of less<>
使用自定义类而不是less<>
This makes things a bit more explicit and allows you to write multiple comparators per class:这使事情更加明确,并允许您为每个类编写多个比较器:
#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);
}
See also也可以看看
I feel your pain.我感觉到你的痛苦。 What makes me mad is that set
and map
are always implemented using the same data-structure under the hood, which is a tree
of values parametrized with a key extractor.让我生气的是set
和map
总是使用相同的数据结构在引擎盖下实现,这是一个用键提取器参数化的值tree
。 Unfortunately there is no such thing in the standard.不幸的是,标准中没有这样的东西。
If boost is OK, use Boost.MultiIndex to achieve what you need.如果 boost 没问题,请使用Boost.MultiIndex来实现您的需求。 Take a look at Boost.Intrusive too.也看看Boost.Intrusive 。
C++ provides the mutable
keyword that would allow you using the second solution -- a set
. C++ 提供了mutable
关键字,允许您使用第二种解决方案—— set
。 Declaring your value as mutable
in your item class will allow modifying it even if the item is const
.在您的项目类中将您的值声明为mutable
将允许修改它,即使该项目是const
。 See also: Does the 'mutable' keyword have any purpose other than allowing the variable to be modified by a const function?另请参阅:除了允许 const 函数修改变量之外,“mutable”关键字还有其他用途吗?
Or, even simpler, implement an accessor for your value that const_cast
s away the constant-ness of the item.或者,更简单的是,为您的值实现一个访问器, const_cast
远离项目的常量性。
... but where the value object itself (and references to it) knows its key ...但是值对象本身(和对它的引用)知道它的键
Map:地图:
The object can't know 'its' key, since a pointer to the same object may be added to several maps, using different keys.对象无法知道“它的”键,因为指向同一个对象的指针可能会被添加到多个映射中,使用不同的键。 The key belongs to a map;密钥属于地图; not to an object.不是对象。
Set:放:
What should happen when the value of this member changes?当这个成员的值发生变化时会发生什么? How would you force a reindexing?您将如何强制重新索引? This is why set enforces constness.这就是 set 强制执行常量的原因。
-- ——
You are trying to index items of a given class based on one of its members, but you don't want to copy this member for indexing purposes, and you don't want to make the object const (I assume that you do want to make the member const).您正在尝试根据其成员之一对给定类的项目进行索引,但您不想复制此成员用于索引目的,并且您不想使对象成为 const(我假设您确实想要使成员为 const)。
I would have built it on top of a Red-Black or AVL tree.我会在红黑树或 AVL 树上构建它。
I'm not familiar enough with Boost.MultiIndex suggested by ybungalobill.我对 ybungalobill 建议的 Boost.MultiIndex 不够熟悉。 I'm not sure whether its instantiated code copies the indexed member, or how it handles values changes for this member.我不确定它的实例化代码是否复制了索引成员,或者它如何处理该成员的值更改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.