C++ 智能指针和无序映射、无序集合等
我需要一个可搜索的guid集合(存储为16字节),其中实际的唯一ID是智能指针结构/类的成员。这是在“上次引用删除”的基础上由其他对象计数和指向的引用-类似于C++ 智能指针和无序映射、无序集合等,c++,hash,map,unordered-map,unordered-set,C++,Hash,Map,Unordered Map,Unordered Set,我需要一个可搜索的guid集合(存储为16字节),其中实际的唯一ID是智能指针结构/类的成员。这是在“上次引用删除”的基础上由其他对象计数和指向的引用-类似于std::shared\u ptr。但由于智能指针类的自定义特性,我不想使用shared\u ptr 但是,我确实希望使用std::unordered_map或std::unordered_set(如果它们足够快)来保存指针集合 尽管智能指针地址是唯一的,因此可以用作哈希,但我需要表中的可搜索键作为GUID;这样我就可以使用find(gui
std::shared\u ptr
。但由于智能指针类的自定义特性,我不想使用shared\u ptr
但是,我确实希望使用std::unordered_map
或std::unordered_set
(如果它们足够快)来保存指针集合
尽管智能指针地址是唯一的,因此可以用作哈希,但我需要表中的可搜索键作为GUID;这样我就可以使用find(guid)
快速找到正确的智能指针
很难用语言来解释,下面是一些代码:
class SmartPointer
{
public:
GUID guid;
int refCount; // Incremented/decremented when things point or stop pointing to it.
void* actualObject; // The actual data attached to the smart pointer.
};
// Generate a unique 128-bit id.
GUID id;
// Create the smart pointer object.
SmartPointer* sp = new SmartPointer();
sp->guid = id;
// Create a set of SmartPointers.
std::unordered_set<SmartPointer*> set;
set.insert(sp);
// Need to find a SmartPointer based on a known GUID and not the pointer itself.
SmartPointer* found = set.find(id);
类智能指针
{
公众:
GUID;
int refCount;//当事物指向或停止指向它时递增/递减。
void*actualObject;//附加到智能指针的实际数据。
};
//生成唯一的128位id。
GUID id;
//创建智能指针对象。
SmartPointer*sp=新的SmartPointer();
sp->guid=id;
//创建一组智能指针。
std::无序_集;
插入(sp);
//需要根据已知GUID而不是指针本身查找SmartPointer。
SmartPointer*found=set.find(id);
我认为在自定义散列/相等函数中进行一些解引用应该可以做到这一点,但我不确定具体如何实现。对于标准散列容器,您需要一个可散列的键(即,可以通过散列算法转换为大小的东西)和键的等价运算符,以防散列冲突(即,两个guid不同,但哈希值相同) 为了通过GUID查找SmartPointer,您可能需要无序的_映射,而不是无序的_集。请参见底部的示例 在任何情况下,有两种方法可以散列自定义类:(1)专门化std::hash或(2)在散列容器的类型定义中提供散列函数和可能的相等函子 专门化std::hash 要专门化智能指针的std::hash,以便它查看GUID,请执行以下操作:
namespace std
{
template<>
struct hash< SmartPointer >
{
size_t operator()( const SmartPointer& sp ) const
{
return hash( sp.guid );
}
};
template<>
struct hash< GUID >
{
size_t operator()( const GUID& id ) const
{
return /* Some hash algo to convert your GUID into a size_t */;
}
};
}
使用带有std::unordered_集的SmartPointer,您只有一个GUID副本,但由于所有哈希机制都在std::unordered_集内部,因此您无法访问哈希键。要在set by GUID中查找它,您需要进行手动搜索,这否定了哈希的优势
要获得所需内容,我认为您需要定义自己的哈希容器,以便从外部对哈希进行更多控制,或者使用类似于侵入式引用计数GUID对象的内容,例如:
class GUID
{
public:
typedef std::vector<std::uint8_t> ID;
int refCount;
ID* actualID;
// ...
};
SmartPointer sp1, sp2;
std::unordered_map< GUID, SmartPointer > m;
m[ sp1.guid ] = sp1;
m[ sp2.guid ] = sp2;
类GUID
{
公众:
typedef std::向量ID;
int refCount;
ID*实现;
// ...
};
智能指针sp1、sp2;
std::无序映射m;
m[sp1.guid]=sp1;
m[sp2.guid]=sp2;
在这种情况下,实现的GUID只存在一个副本,即使它是映射的键和映射中的值的成员,但它的引用计数设备将有多个副本
在64位系统上,计数可以是32位,指针可以是64位,这意味着GUID对象的每个副本总共有12个字节,每个实际GUID可以节省4个字节。使用32位计数器和指针,每个GUID可以节省8个字节,使用64位计数器和指针,它将占用与GUID数据相同的空间。前两种方法之一在您的应用程序/平台中可能值得,也可能不值得,但最后一个可能不值得
如果是我,我只需复制一个GUID对象作为密钥,直到根据测量结果我知道它是不可接受的。然后我可以优化GUID对象的实现,使其在不影响用户代码的情况下进行内部引用计数。您编写自己的智能指针类而不是使用现有的智能指针类有什么原因吗您可以看到您创建的实现中存在一些问题。您只需要实现自己的哈希函子,它接受一个
SmartPointer*
,并执行正确的操作。然后用它实例化映射。请参阅。请记住,OP正在他/她的映射中存储SmartPointer*
。此外,unary\u函数也在C++11中被弃用。注意到并删除了。我确实对OP的代码做了一些更改,但这个想法仍然有效。感谢metal。是的,这个想法看起来与我的想法非常接近。但问题是,它将意味着存储两个版本的GUID,一个在智能指针中,另一个在映射中。这将受到限制,因为我可能想要存储数百万个智能指针指针,并且只需要GUID的一个副本,该GUID必须在smartpointer类本身中。因此需要从映射中指向smartpointer的指针。映射应以与任何其他对象相同的方式引用smartpointer(引用计数)没有考虑到各种指针相对于GUID大小的潜在大小。我可能会使用ID的副本作为映射中的键,正如您所说的,并且只有在以后出现问题时才会重新考虑。谢谢。
#include <vector>
#include <cstdlib>
#include <cstdint>
#include <algorithm>
#include <cassert>
#include <unordered_map>
class GUID // Some goofy class. Yours is probably better
{
public:
std::vector<uint8_t> _id;
GUID()
: _id(16)
{
std::generate(_id.begin(),_id.end(), std::rand);
}
friend bool operator ==( const GUID& g1, const GUID& g2 )
{
return std::equal( g1._id.begin(), g1._id.end(), g2._id.begin() );
}
friend bool operator !=( const GUID& g1, const GUID& g2 )
{
return !(g1 == g2);
}
};
class SmartPointer
{
public:
GUID guid;
int refCount; // Incremented/decremented when things point or stop pointing to it.
void* actualObject; // The actual data attached to the smart pointer.
friend bool operator ==( const SmartPointer& p1, const SmartPointer& p2 )
{
// This may not be right for you, but good enough here
return p1.guid == p2.guid;
}
};
struct HashGUID
{
std::size_t operator()( const GUID& guid ) const
{
// Do something better than this. As a starting point, see:
// http://en.wikipedia.org/wiki/Hash_function#Hash_function_algorithms
return std::accumulate( guid._id.begin(), guid._id.end(), std::size_t(0) );
}
};
int main()
{
// Create the smart pointer object.
SmartPointer sp1, sp2, sp3;
assert( sp1.guid != sp2.guid );
assert( sp1.guid != sp3.guid );
assert( sp2.guid != sp3.guid );
// Create a set of SmartPointers.
std::unordered_map<GUID, SmartPointer, HashGUID> m;
m[sp1.guid] = sp1;
m[sp2.guid] = sp2;
m[sp3.guid] = sp3;
const GUID guid1 = sp1.guid;
const GUID guid2 = sp2.guid;
const GUID guid3 = sp3.guid;
// Need to find a SmartPointer based on a known GUID and not the pointer itself.
auto found1 = m.find( guid1 );
auto found2 = m.find( guid2 );
auto found3 = m.find( guid3 );
assert( found1 != m.end() );
assert( found2 != m.end() );
assert( found3 != m.end() );
assert( found1->second == sp1 );
assert( found2->second == sp2 );
assert( found3->second == sp3 );
}
class SmartPointer
{
public:
int refCount; // Incremented/decremented when things point or stop pointing to it.
struct
{
GUID guid;
void* actualObject; // The actual data attached to the smart pointer.
} *refCountedData;
};
class GUID
{
public:
typedef std::vector<std::uint8_t> ID;
int refCount;
ID* actualID;
// ...
};
SmartPointer sp1, sp2;
std::unordered_map< GUID, SmartPointer > m;
m[ sp1.guid ] = sp1;
m[ sp2.guid ] = sp2;