我正在寻找一种C ++数据结构,它允许我将对象与唯一的数值(一个键)相关联,并且在从容器中删除相应的对象之后将重新使用这些键。所以它基本上是混合地图/队列结构。我目前的实施是
std::map<size_t, TObject>
我插入这样的对象:
size_t key = (m_Container.end()--)->first + 1;
m_Container[key] = some_object;
它适用于我的目的(我永远不会分配超过size_t对象);但我仍然想知道是否有一个更专业的容器,最好已经在stl或boost中,或者有一种方法可以使用另一个容器来实现这个目标。
(当然我可以,而不是在我的地图中添加最高密钥并添加一个,每次都通过地图并搜索第一个可用密钥,但这会降低从O(1)到O(n)的复杂性如果API是一个简单的
,那也很好size_t new_key = m_Container.insert(object);
)。
有什么想法吗?
答案 0 :(得分:1)
如果您永远不会分配超过size_t
个密钥,那么我建议您只使用静态计数器:
size_t assign_id()
{
static size_t next_id;
return next_id++;
}
如果你想要一个不错的API:
template<class Container>
size_t insert(Container & container, TObject const & obj)
{
container.insert(obj);
return assign_id();
}
std::set<TObject> m_Container;
size_t new_key = insert(m_Container, object);
答案 1 :(得分:1)
我不确定你的ID究竟是什么。碰巧,每个对象都有一个唯一的ID:它的地址!没有两个具有相同地址的不同对象,并且对象的地址在其生命周期内不会改变。
std::set<T>
通常将其T值存储为较大节点的成员,而不是独立对象。但是,T子对象永远不会移动,因此它们的地址也是稳定的唯一标识符。
答案 2 :(得分:1)
创建已删除密钥的std::set<key_type> removed_keys;
。如果removed_keys
不为空,则使用removed_keys
中的密钥,否则创建新密钥。
答案 3 :(得分:0)
std::vector<TObject> m_Container;
size_t key = m_Container.size();
m_Container.push_back(some_object);
当然,如果您有其他使用特征,这可能完全没用。但由于你只描述了插入和键的需要(如此提取),很难给出任何其他明确的答案。但是从这两个要求中,std :: vector&lt;&gt;应该工作得很好。
如果你有一些其他的使用特性,例如:(元素可以删除),(我们在大块中插入元素),(我们不经常插入元素)等等,这些可能会改变人们给出的建议。
您提到要搜索未使用的元素ID。这表明您可能正在删除元素,但我没有看到任何明确的要求或用法,其中元素被删除。
size_t key = (m_Container.end()--)->first + 1;
这不符合您的想法 它也是等同的:
size_t key = m_Container.end()->first + 1;
m_Container.end()--;
帖子减量运算符会修改左值。但表达式的结果是原始值。因此,您正在应用运算符 - &gt;到end()返回的值。这(可能)是未定义的行为。
参见标准:
章节:5.2.6递增和递减
后缀++表达式的值是其操作数的值。
m_Container.end()-- // This sub-expresiion returns m_Container.end()
#include <vector>
template<typename T>
class X
{
public:
T const& operator[](std::size_t index) const {return const_cast<X&>(*this)[index];}
T& operator[](std::size_t index) {return data[index];}
void remove(std::size_t index) {unused.push_back(index);}
std::size_t insert(T const& value);
private:
std::vector<T> data;
std::vector<std::size_t> unused;
};
template<typename T>
std::size_t X<T>::insert(T const& value)
{
if (unused.empty())
{
data.push_back(value);
return data.size() - 1;
}
std::size_t result = unused.back();
unused.pop_back();
data[result] = value;
return result;
}
答案 4 :(得分:0)
是否有理由要求std::map
不删除键,值对?
这听起来像是过早优化的尝试。
方法是用虚拟或占位符值替换值部分。从长远来看,问题是只要密钥存在,就可以从std::map
中提取虚拟值。每次访问std::map
时,您都需要添加虚拟值检查。
因为您想要维护没有值的键,所以您很可能必须编写自己的容器。当客户端在没有值时访问密钥时,您将特别需要设计代码来处理这种情况。
使用标准容器和没有值对的密钥看起来没有性能提升。但是,就内存而言,可能是一个增益。您的问题会减少动态内存的碎片化;因此不必为同一个密钥重新分配内存。你必须决定权衡。