为类的每个实例分配唯一 ID
Assigning Unique ID's to each instance of a class
我正在从XML文件导入项。每个XML元素(FoodItem
, Person
, Order
, CoffeeRun
)都是一个类&这些元素中的每一个都有一个唯一的ID(该类的唯一ID)。
<person>
<id>0</id>
<name>...</name>
</person>
<FoodItem>
<id>0</id>
<name>Coffee</name>
</FoodItem>
我正试图开发一个子类DatabaseItem
,这确保一个类的2个对象具有相同的ID。你能帮我,帮我开发一个有效的算法来确保没有对象具有相同的ID吗?
我的两种方法对我来说似乎有点低效:
使用包含到目前为止所有USED id的静态类向量。当创建一个新的
DatabaseID( int requestedID )
对象时,我检查ID是否可用,通过检查向量中所有使用的值来检查ID是否已经存在,我认为这是大o 'n速度?使用静态类bool
vector
,其中vector
的每个元素对应于一个id(因此vector[1]
将对应于id为1的对象)。我检查是否已经通过查看vector
中的元素是否为trueif ( v[nID] == true ) { // this ID is already taken }
来获取id。这看起来效率很低,因为这意味着我的vector
将占用大量内存,对吗?- 我不熟悉在c++中使用地图,但也许我应该在这里使用一个?
任何关于有效算法的建议都将非常有帮助:
class DatabaseItem
{
public:
static unsigned int instanceCount;
DatabaseItem()
{
// Assign next available ID
}
DatabaseItem( unsigned int nID )
{
// Check that that id is not already taken
// if id is taken, look for next available id &
// give the item that id
}
private:
unsigned int uniqueID;
};
// My solution: Do you have any better ideas that ensure no objects jave the same ID?
// This seems REALLY inefficient...
class DatabaseItem
{
public:
static unsigned int instanceCount;
static vector <unsigned int> usedIDs;
DatabaseItem()
{
DatabaseItem::instanceCount++;
uniqueID = instanceCount;
usedIDs.add( instanceCount );
}
DatabaseItem( unsigned int nID )
{
if ( isIDFree( nID ) )
{
uniqueID = nID;
}
else uniqueID = nextAvailableID();
DatabaseItem::instanceCount++;
}
bool isIDFree( unsigned int nID )
{
// This is pretty slow to check EVERY element
for (int i=0; i<usedIDs.size(); i++)
{
if (usedIDs[i] == nID)
{
return false;
}
}
return true;
}
unsigned int nextAvailableID()
{
while ( true )
{
unsigned int ID = 0;
if ( isIDFree( ID ) )
{
return ID;
}
else ID++;
}
}
private:
unsigned int uniqueID;
};
// Alternate that uses boolean vector to track which ids are occupied
// This means I take 30000 boolean memory when I may not need all that
class DatabaseItem
{
public:
static unsigned int instanceCount;
static const unsigned int MAX_INSTANCES = 30000;
static vector <bool> idVector;
// Is this how I initialise a static class vector...? (note this code will be outside the class definition)
// vector <bool> DatabaseItem::idVector( MAX_INSTANCES, false );
DatabaseItem()
{
uniqueID = nextAvailableID();
idVector[uniqueID] = true;
}
DatabaseItem( unsigned int nID )
{
if ( nID >= MAX_INSTANCES )
{
// not sure how I shd handle this case?
}
if ( idVector[nID] == false )
{
uniqueID = nID;
idVector[nID] = true;
}
else
{
uniqueID = nextAvailableID();
idVector[uniqueID] = true;
}
instanceCount++;
}
unsigned int nextAvailableID()
{
for (int i=0; i<idVector.size(); i++)
{
if ( !idVector[i] )
{
return i;
}
}
return -1;
}
bool isIDFree( unsigned int nID )
{
// Note I cannot do this: Because I am using Mosync API & it doesn't support any C++ exceptions'
// I declare idVector with no size! so not idVector( 30000, false)... just idVector;
// then I allow an exception to occur to check if an id is taken
try
{
return idVector[nID];
}
catch (...)
{
return true;
}
}
private:
unsigned int uniqueID;
};
vector<bool>
是用每个bool值一个比特来实现的,所以它不会像你想象的那样浪费那么多空间。
set<unsigned int>
是一个简单的解决方案。vector<bool>
更快。两者都需要一点内存。根据您的使用模式,还有一些其他的解决方案:
-
一个
unsigned int all_taken_upto_this;
和一个set<int>
组合在一起,覆盖了所有比all_taken_upto_this
高的古怪ID -从集合中删除并在可能的情况下增加计数器 -
逻辑上被视为已取序列或自由序列的
begin,end
的map<unsigned int, unsigned int>
。要正确实现这一点需要一点时间(例如,当你在两个元素之间添加最后一个ID时合并连续的地图元素)
你可以使用一个预制的"sparse bitset"类型的数据结构——我不知道OTOH的任何实现。
根据元素的数量和其他一些问题,您可能会考虑将它们(或至少是指向它们的指针)实际存储在映射中。这将是相当简单的实现,但将占用一些空间。另一方面,它将通过id
为您提供快速查找,如果XML中有交叉引用,这可能是一个明显的优势。映射(假设有指针)如下所示:
std::map<int, std::shared_ptr<Object> > id_map;
std::shared_ptr<Object> p( new Object( xml ) );
if ( !id_map.insert( std::make_pair( p->id, p ) ).second ) {
// failed to insert, the element is a duplicate!!!
}
如果您没有被锁定使用整数,您可以查看guid(全局唯一id)。根据所使用的平台,通常可以找到一些实用程序函数来动态生成GUID。如果使用Visual Studio,我使用了CoCreateGuid函数。
如果你被锁定为32位整数,另一个选择是哈希表。如果每个XML元素都是唯一的,那么散列函数可以生成唯一的散列值。根据数据集的大小,仍然有很小的碰撞概率。我用过的这个与我使用过的数据集碰撞率很低的叫做Jenkins哈希函数
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 何时在引用或唯一指针上使用移动语义
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 计算排序向量的向量中唯一值的计数
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 如何使用Visual Studio 2017在C++中为参数化对象数组使用唯一指针
- 堆分配的对象是否存在永不为空的唯一所有者?
- 如何在C++中为增加但记住删除先前对象的对象分配唯一标识符
- 唯一指针是否在堆或堆栈上分配内存?
- 在C++中为零大小的分配返回唯一地址背后的基本原理是什么?
- 为字符串中的每个字符(不是字符位置!)分配唯一的索引
- 如何使具有包含唯一指针的成员变量的类可复制可分配
- 在另一个线程中分配唯一ptr的错误
- 为类型分配唯一的整型标识符,编译时
- 为类的每个实例分配唯一 ID