将唯一ID映射到对象的数据结构

时间:2010-02-10 11:44:20

标签: c++ data-structures stl

我正在寻找一种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);

)。

有什么想法吗?

5 个答案:

答案 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时,您都需要添加虚拟值检查。

因为您想要维护没有值的键,所以您很可能必须编写自己的容器。当客户端在没有值时访问密钥时,您将特别需要设计代码来处理这种情况。

使用标准容器和没有值对的密钥看起来没有性能提升。但是,就内存而言,可能是一个增益。您的问题会减少动态内存的碎片化;因此不必为同一个密钥重新分配内存。你必须决定权衡。