将唯一id映射到对象的数据结构 < >我正在寻找一个C++数据结构,它允许我将对象与一个唯一的数值(键)关联起来,并且在从容器中移除相应对象之后,将重新使用这些键。所以它基本上是一种混合映射/队列结构。我当前的实现是一个 std::map<size_t, TObject>

将唯一id映射到对象的数据结构 < >我正在寻找一个C++数据结构,它允许我将对象与一个唯一的数值(键)关联起来,并且在从容器中移除相应对象之后,将重新使用这些键。所以它基本上是一种混合映射/队列结构。我当前的实现是一个 std::map<size_t, TObject>,c++,data-structures,stl,C++,Data Structures,Stl,就我的目的而言,这很好(我永远不会分配超过大小的对象);但我仍然想知道是否有一个更专门的容器可用,最好已经在stl或boost中,或者有一种方法可以使用另一个容器来实现这个目标 (当然,我可以,而不是在我的映射中获取最高的键并添加一个,每次遍历映射并搜索第一个可用的键,但这会将复杂性从O(1)降低到O(n)。如果API是一个简单的 size_t new_key = m_Container.insert(object); ) 有什么想法吗?如果您永远不会分配超过size\t的密钥,那么我建议您只

就我的目的而言,这很好(我永远不会分配超过大小的对象);但我仍然想知道是否有一个更专门的容器可用,最好已经在stl或boost中,或者有一种方法可以使用另一个容器来实现这个目标

(当然,我可以,而不是在我的映射中获取最高的键并添加一个,每次遍历映射并搜索第一个可用的键,但这会将复杂性从O(1)降低到O(n)。如果API是一个简单的

size_t new_key = m_Container.insert(object);
)


有什么想法吗?

如果您永远不会分配超过
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);
模板
尺寸插入件(容器和容器、待工程量和对象)
{
容器。插入(obj);
返回assign_id();
}
std::设置m_容器;
size\u t new\u key=插入(m\u容器、对象);

我不确定您到底想从ID中得到什么。事实上,每个对象都有一个唯一的ID:它的地址!没有两个具有相同地址的不同对象,并且对象的地址在其生存期内不会更改

std::set
通常将其T值存储为较大节点的成员,而不是独立对象。尽管如此,T子对象从未移动过,因此它们的地址也是稳定、唯一的标识符。

Create
std::set removed\U keys。如果
removed\u keys
不为空,则使用
removed\u keys
中的key,否则创建一个新的key。

为什么不使用向量? 这不是在做你认为它在做的事。
这也相当于:

size_t key = m_Container.end()->first + 1;
m_Container.end()--;
post减量运算符修改左值。但表达式的结果是原始值。因此,将运算符->应用于end()返回的值。这(可能)是未定义的行为

见标准:

第5.2.6节增量和减量
后缀++表达式的值是其操作数的值

备选方案:
#包括
模板
X类
{
公众:
常量和运算符[](std::size_T index)常量{return const_cast(*this)[index];}
运算符[](std::size_T index){返回数据[index];}
void remove(std::size_t index){unused.push_back(index);}
标准:尺寸插入(常数和值);
私人:
std::矢量数据;
std::未使用的载体;
};
模板
std::size\u t X::insert(t常量和值)
{
if(unused.empty())
{
数据。推回(值);
返回数据。size()-1;
}
std::size\u t result=unused.back();
未使用的;
数据[结果]=数值;
返回结果;
}

是否有理由需要
std::map
不删除密钥、值对

这听起来像是一种过早优化的尝试

一种方法是用虚拟值或占位符值替换值部分。从长远来看,问题在于只要键存在,就可以从
std::map
中提取虚拟值。每次访问
std::map
时,您都需要添加对伪值的检查

因为您希望维护一个没有值的键,所以很可能必须编写自己的容器。您尤其需要设计代码来处理客户机在没有值的情况下访问密钥的情况


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

当容器为空时(
end==begin
)这种情况就会中断。另外,您可能错过了
m_Container.back()
。在我的代码中,我确实检查了地图是否为空,这只是为了说明。此外,std::map没有.back().m_Container.rbegin()->first可能比(m_Container.end()-->)first更具可读性?正确。不过,随着瓦伦丁节的到来,我想()--->会很好地融入花卉主题;)注意:后减量运算符(--)使左值表达式减量。但是表达式的结果(返回到表达式进行进一步处理)是原始值。因此,在end()上使用了运算符->用于获取第一个(一个无效操作)。
对象
new_键
如何相互关联?容器不应该是一个
map
而不是
set
?我认为OP会自己处理这个问题(可能是通过将密钥存储在对象的数据成员中)。此外,OP似乎只是为了保留一些到目前为止创建的对象而使用map。这就是为什么我建议将我的函数作为一种更轻量级的方法来实现相同的效果。我需要一种方法来以一种不引人注目的方式跟踪对象,即不改变被跟踪的对象(因此不添加ID)。即使我分配了ID,我仍然需要在创建一个新对象时找出最新的ID,仅仅是转移问题。我需要跟踪对象,以知道哪些对象仍在队列中待处理,哪些已完成。我的代码解决了知道最新ID是什么的问题。如果您还需要为每个对象附加一个ID,那么我建议您将我的代码与
map
结合使用。我需要“按值”标识对象,将对象的副本传递给单独的线程,并执行一个操作
std::vector<TObject> m_Container;

size_t key = m_Container.size();
m_Container.push_back(some_object);
size_t key = (m_Container.end()--)->first + 1;
size_t key = m_Container.end()->first + 1;
m_Container.end()--;
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;
}