这篇文章真的是我最近最想写的一篇文章,倒不是本文所述的知识点有多高级,而是因为这个知识点比较讨巧——太骚了,哈哈哈。且听我慢慢道来。
当一个系统内存在很多个对象且希望能够操作任意指定的对象时,对象需要提供一个唯一标识符,可以是独一无二的名字,也可以是GUID,但是:
虽然GUID太长,但是我们仍旧可以借用其思路来选择一个数字作为唯一标识符。
在C++中,每个对象在内存中都有一个地址,可以认为存在如下的流程:
在32位软件中,对象的内存地址为32位4个字节,在64位软件中,对象的内存地址为64位8个字节,所以如果代码要同时支持32位和64位,则应该是使用64位来存储内存地址。毕竟64位可以存储32位、64位的内存地址,但是32位不能存储64位的内存地址。 所以该唯一标识符应该使用uint64_t类型来存储。具体的使用方式如下:
#include <iostream>
class Test{
public:
Test(){
m_id = reinterpret_cast<uint64_t>(this);
}
~Test(){
m_id = 0;
}
uint64_t GetId() const{
return m_id;
}
private:
uint64_t m_id;
};
int main(){
Test t1;
Test t2;
std::cout << "t1 id: " << t1.GetId() << std::endl;
std::cout << "t2 id: " << t2.GetId() << std::endl;
auto new_t1 = new Test();
auto new_t2 = new Test();
std::cout << "new_t1 id: " << new_t1->GetId() << std::endl;
std::cout << "new_t2 id: " << new_t2->GetId() << std::endl;
return 0;
}
//x64输出:
// t1 id: 368160273736
// t2 id: 368160273768
// new_t1 id: 2076629290624
// new_t2 id: 2076629291104
//x86输出:
// t1 id: 9435020
// t2 id: 9435004
// new_t1 id: 13305544
// new_t2 id: 13306664
经过测试,x64和x86下均可以正常使用,且内存地址是唯一的,所以该方案是可行的。
使用内存地址转为uint64_t作为唯一标识符,有如下优势:
但是这种方法也存在其限制,对象存续期间该标识符是唯一的,当对象被析构后,地址可能会被重用,从而导致地址并不是唯一的,进而影响唯一性。
本文介绍了使用内存地址作为唯一标识符的骚操作,该操作具有唯一性、长度适中、架构无关等优势,是一个值得推荐的操作。