一、c++ boost::uuid 详解
1、引言:为什么需要 uuid?
在分布式系统、数据库设计、消息队列和微服务架构中,生成全局唯一的标识符是一个常见且关键的需求。传统的自增 id 在分布式环境下存在瓶颈,而简单的随机字符串又难以保证唯一性。这时,uuid(universally unique identifier,通用唯一识别码) 便成为了理想的选择。
boost c++ 库提供了强大且高效的 boost::uuid 模块,它严格遵循 rfc 4122 标准,支持多种 uuid 版本(1, 3, 4, 5),并深度集成于 boost 生态(如 boost::hash、序列化等)。
2、环境准备与 boost 安装
项目配置(cmake 示例)
cmake_minimum_required(version 3.10) project(boost_uuid_demo) find_package(boost 1.85.0 required components uuid) add_executable(demo main.cpp) target_link_libraries(demo boost::uuid)
3、 boost::uuid 核心类与基础用法
3.1、 基本类型与头文件
#include <boost/uuid/uuid.hpp> // uuid 类
#include <boost/uuid/uuid_generators.hpp> // 生成器
#include <boost/uuid/uuid_io.hpp> // 流输出/格式化
#include <iostream>
int main() {
// 声明一个 uuid 对象(默认全零)
boost::uuids::uuid id;
std::cout << "default uuid: " << id << std::endl; // 输出:00000000-0000-0000-0000-000000000000
return 0;
}
3.2 、主要生成器(generators)
boost 提供了多种符合 rfc 4122 的生成器:
| 生成器类 | uuid 版本 | 描述 | 适用场景 |
|---|---|---|---|
random_generator | v4 | 基于强随机数 | 最常用,需要高随机性且不关心时间/机器信息时 |
nil_generator | - | 生成全零 uuid | 作为占位符或未初始化状态 |
string_generator | - | 从字符串解析 | 反序列化、数据库读取 |
name_generator | v3/v5 | 基于命名空间和名称的 sha-1 哈希 | 需要确定性、可重复生成的 id(如内容寻址) |
4、实战:四种 uuid 的生成与解析
4.1 、版本 4:随机 uuid(最常用)
#include <boost/uuid/random_generator.hpp> #include <boost/uuid/uuid_io.hpp> boost::uuids::random_generator gen; boost::uuids::uuid id = gen(); // 每次调用生成一个随机的 v4 uuid std::cout << "random uuid (v4): " << id << std::endl; // 示例输出:f47ac10b-58cc-4372-a567-0e02b2c3d479
4.2、 版本 1:基于时间戳和 mac 地址
#include <boost/uuid/uuid_generators.hpp> // 注意:需要链接 boost.date_time 库 boost::uuids::uuid id = boost::uuids::random_generator()(); // v1 生成器已不推荐,通常用 v4 // 现代实践中,v1 较少使用,因其会暴露 mac 地址信息。
4.3 、版本 3 & 5:基于名称的 uuid(命名空间 uuid)
#include <boost/uuid/name_generator.hpp>
#include <boost/uuid/uuid.hpp>
// 定义命名空间 uuid(例如 dns 命名空间)
boost::uuids::uuid ns_dns = { /* dns namespace uuid: 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1,
0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8
};
// 创建 v5 (sha-1) 名称生成器
boost::uuids::name_generator_v5 gen_v5(ns_dns);
boost::uuids::uuid id_v5 = gen_v5("www.example.com");
std::cout << "name-based uuid (v5): " << id_v5 << std::endl;
// 对于相同的命名空间和名称,生成的 uuid 永远相同。4.4、 从字符串解析与格式化
#include <boost/uuid/string_generator.hpp>
#include <sstream>
boost::uuids::string_generator str_gen;
// 从标准格式字符串解析
std::string uuid_str = "123e4567-e89b-12d3-a456-426614174000";
boost::uuids::uuid id = str_gen(uuid_str);
// 验证解析是否成功(无效字符串会抛出异常)
try {
auto id2 = str_gen("invalid-uuid-string");
} catch (const std::runtime_error& e) {
std::cerr << "parse failed: " << e.what() << std::endl;
}
// 自定义格式化(无连字符)
std::stringstream ss;
ss << std::hex << std::nouppercase << std::setfill('0');
for (unsigned char byte : id) {
ss << std::setw(2) << static_cast<int>(byte);
}
std::cout << "raw hex: " << ss.str() << std::endl;5、 高级特性与性能优化
5.1、 内存布局与大小
boost::uuid 本质上是一个 std::array<unsigned char, 16> 的类型别名,占用 16 字节 连续内存,适合作为值类型传递和存储。
static_assert(sizeof(boost::uuids::uuid) == 16, "uuid must be 16 bytes"); static_assert(std::is_trivially_copyable_v<boost::uuids::uuid>, "uuid should be trivially copyable");
5.2 、哈希支持(用于 std::unordered_map)
#include <boost/uuid/uuid.hpp> #include <unordered_map> // boost 已为 uuid 特化了 std::hash std::unordered_map<boost::uuids::uuid, std::string> cache; boost::uuids::random_generator gen; auto key = gen(); cache[key] = "some_data"; // 也可以使用 boost::hash(需包含 <boost/functional/hash.hpp>) #include <boost/functional/hash.hpp> size_t h = boost::hash<boost::uuids::uuid>()(key);
5.3 、序列化(boost.serialization)
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/array.hpp>
#include <fstream>
struct mydata {
boost::uuids::uuid id;
int value;
template<class archive>
void serialize(archive& ar, const unsigned int version) {
ar & id & value;
}
};
// 保存
mydata data{gen(), 42};
std::ofstream ofs("data.txt");
boost::archive::text_oarchive oa(ofs);
oa << data;
// 加载
std::ifstream ifs("data.txt");
boost::archive::text_iarchive ia(ifs);
mydata loaded;
ia >> loaded;5.4、 随机数生成器的线程安全与性能
boost::uuids::random_generator 内部使用 boost::random::random_device 或 boost::random::mt19937 作为随机源。对于高性能多线程场景:
// 方案1:每个线程使用独立的生成器(推荐)
thread_local boost::uuids::random_generator tls_gen;
// 方案2:使用静态生成器并加锁(性能较低)
static boost::uuids::random_generator static_gen;
static std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
auto id = static_gen();
}6、 常见问题与陷阱(faq)
6.1、 如何判断 uuid 是否为 nil(全零)?
boost::uuids::uuid id;
if (id.is_nil()) {
std::cout << "uuid is nil (uninitialized)" << std::endl;
}
6.2、 版本与变体(variant)如何获取?
boost::uuids::uuid id = gen(); auto version = id.version(); // 返回 1, 3, 4, 5 或 0(未知) auto variant = id.variant(); // 返回 variant 类型(通常为 rfc 4122 变体)
6.3 、字符串大小写敏感吗?
不敏感。string_generator 解析时忽略大小写,但 operator<< 输出默认小写。可使用 std::uppercase 控制输出格式。
6.4、 在数据库中的存储
建议存储为 16 字节的 binary(16) 或 36 字节的 char(36)(包含连字符)。前者更节省空间且查询更快。
-- mysql
create table items (
id binary(16) primary key,
name varchar(255)
);
-- 插入时使用 uuid 的字节数组
insert into items (id, name) values (unhex(replace('f47ac10b-58cc-4372-a567-0e02b2c3d479', '-', '')), 'test');7、 与现代 c++ 的集成(c++11/17/20)
7.1 、范围 for 循环与结构化绑定
boost::uuids::uuid id = gen();
// 遍历字节
for (unsigned char byte : id) {
std::cout << std::hex << static_cast<int>(byte) << ' ';
}
// 转换为字节数组(c++17)
std::array<unsigned char, 16> arr = *reinterpret_cast<std::array<unsigned char, 16>*>(&id);7.2 、与std::string_view配合
#include <string_view>
std::string str = to_string(id);
std::string_view sv(str);
// 避免复制,直接操作字符串视图
if (sv.starts_with("123e")) {
// ...
}7.3、 自定义格式化器(c++20std::format)
// 等待 boost 适配 std::format,目前可自定义:
#include <fmt/format.h> // 或 {fmt} 库
template <>
struct fmt::formatter<boost::uuids::uuid> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename formatcontext>
auto format(const boost::uuids::uuid& id, formatcontext& ctx) {
return format_to(ctx.out(), "{}", to_string(id));
}
};
// 使用
boost::uuids::uuid id = gen();
std::string s = fmt::format("uuid: {}", id);8、 总结与最佳实践
- 版本选择:
- 默认使用 v4 (随机):适用于绝大多数需要唯一 id 的场景。
- 需要确定性 id 时使用 v5:例如,基于内容生成永久性标识符。
- 避免使用 v1:除非有特定时间排序需求且不介意暴露 mac 地址信息。
- 性能关键路径:
- 使用
thread_local生成器避免锁竞争。 - 优先使用二进制(16字节)格式进行网络传输和数据库存储。
- 使用
- 可读性与调试:
- 日志和配置文件中使用带连字符的标准字符串格式。
- 重载
operator<<以便于调试输出。
- 未来兼容性:
- boost.uuid api 非常稳定,可放心用于长期项目。
- 关注 c++ 标准库未来可能引入的
<uuid>提案,但 boost 版本仍是当前事实标准。
二、代码示例
1、示例代码
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/functional/hash.hpp>
#include <boost/random.hpp>
namespace bu = boost::uuids;
void print_uuid_bytes(const bu::uuid& u)
{
std::cout << "raw bytes: ";
const std::uint8_t* p = u.data();
for (std::size_t i = 0; i < 16; ++i)
{
printf("%02x ", p[i]);
}
std::cout << "\n";
}
int main()
{
// 1. nil uuid:只用默认构造,不写 () / {} 避免歧义
bu::uuid nil_uuid;
std::cout << "1. nil uuid: " << nil_uuid << "\n";
std::cout << "is_nil() = " << std::boolalpha << nil_uuid.is_nil() << "\n";
print_uuid_bytes(nil_uuid);
std::cout << "----------------------------------------\n\n";
// 2. v4 随机 uuid
bu::random_generator v4_gen;
bu::uuid v4_uuid = v4_gen();
std::cout << "2. v4 random uuid: " << v4_uuid << "\n";
print_uuid_bytes(v4_uuid);
// 自定义 mt19937 随机源
boost::random::mt19937 mt_rng(12345);
bu::basic_random_generator<boost::random::mt19937> seeded_gen(mt_rng);
bu::uuid seeded_v4 = seeded_gen();
std::cout << "custom seeded v4 uuid: " << seeded_v4 << "\n";
std::cout << "----------------------------------------\n\n";
// 4. 字符串解析 uuid
std::string uuid_str = "550e8400-e29b-41d4-a716-446655440000";
bu::string_generator str_gen;
bu::uuid from_str = str_gen(uuid_str);
std::cout << "4. parse from string: " << from_str << "\n";
print_uuid_bytes(from_str);
std::cout << "----------------------------------------\n\n";
// 5. 二进制缓冲区构造 uuid
std::vector<std::uint8_t> bin_data = {
0x55,0x0e,0x84,0x00,0xe2,0x9b,0x41,0xd4,
0xa7,0x16,0x44,0x66,0x55,0x44,0x00,0x00
};
bu::uuid from_bin;
std::copy(bin_data.begin(), bin_data.end(), from_bin.data());
std::cout << "5. construct from binary buffer: " << from_bin << "\n";
print_uuid_bytes(from_bin);
std::cout << "----------------------------------------\n\n";
// 6. uuid 字符串互转
std::string s = bu::to_string(v4_uuid);
std::cout << "6. to_string(): " << s << "\n";
std::wstring ws = bu::to_wstring(v4_uuid);
std::wcout << l"to_wstring(): " << ws << l"\n";
std::stringstream ss;
ss << v4_uuid;
std::string s_ss = ss.str();
std::cout << "stringstream output: " << s_ss << "\n";
std::cout << "----------------------------------------\n\n";
// 7. 比较运算符
bu::uuid u1 = v4_gen();
bu::uuid u2 = v4_gen();
std::cout << "7. compare operators\n";
std::cout << "u1 = " << u1 << "\n";
std::cout << "u2 = " << u2 << "\n";
std::cout << "u1 == u2: " << (u1 == u2) << "\n";
std::cout << "u1 != u2: " << (u1 != u2) << "\n";
std::cout << "u1 < u2: " << (u1 < u2) << "\n";
std::cout << "u1 > u2: " << (u1 > u2) << "\n";
std::cout << "----------------------------------------\n\n";
// 8. hash 无序容器
std::cout << "8. unordered_map with boost::hash<uuid>\n";
std::unordered_map<bu::uuid, std::string, boost::hash<bu::uuid>> uuid_map;
uuid_map[v4_uuid] = "v4 random";
uuid_map[from_str] = "parsed string uuid";
for (const auto& pair : uuid_map)
{
std::cout << "key: " << pair.first << " | val: " << pair.second << "\n";
}
std::cout << "----------------------------------------\n\n";
// 9. 修改原始字节
std::cout << "9. modify raw bytes via data()\n";
bu::uuid mod_uuid = v4_uuid;
std::uint8_t* mod_buf = mod_uuid.data();
mod_buf[0] = 0xff;
mod_buf[1] = 0xaa;
std::cout << "modified uuid: " << mod_uuid << "\n";
print_uuid_bytes(mod_uuid);
std::cout << "----------------------------------------\n\n";
// 10. 二进制序列化/反序列化
std::cout << "10. binary serialize & restore\n";
std::uint8_t buf[16] = { 0 };
std::copy(v4_uuid.data(), v4_uuid.data() + 16, buf);
bu::uuid restore_uuid;
std::copy(buf, buf + 16, restore_uuid.data());
std::cout << "original: " << v4_uuid << "\n";
std::cout << "restored: " << restore_uuid << "\n";
std::cout << "equal: " << (v4_uuid == restore_uuid) << "\n";
return 0;
}2、运行结果
1. nil uuid: 00000000-0000-0000-0000-000000000000 is_nil() = true raw bytes: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ---------------------------------------- 2. v4 random uuid: dbf8440f-089a-472a-aee4-ebf1bc6446ea raw bytes: db f8 44 0f 08 9a 47 2a ae e4 eb f1 bc 64 46 ea custom seeded v4 uuid: e251fbed-e52d-41e3-9dfd-fd5081087621 ---------------------------------------- 4. parse from string: 550e8400-e29b-41d4-a716-446655440000 raw bytes: 55 0e 84 00 e2 9b 41 d4 a7 16 44 66 55 44 00 00 ---------------------------------------- 5. construct from binary buffer: 550e8400-e29b-41d4-a716-446655440000 raw bytes: 55 0e 84 00 e2 9b 41 d4 a7 16 44 66 55 44 00 00 ---------------------------------------- 6. to_string(): dbf8440f-089a-472a-aee4-ebf1bc6446ea to_wstring(): dbf8440f-089a-472a-aee4-ebf1bc6446ea stringstream output: dbf8440f-089a-472a-aee4-ebf1bc6446ea ---------------------------------------- 7. compare operators u1 = 610f7ff1-9b09-46fa-ba27-cb4bae9cf2e6 u2 = 98b7d23f-eb1f-4244-a04c-2c8555e7ad2b u1 == u2: false u1 != u2: true u1 < u2: true u1 > u2: false ---------------------------------------- 8. unordered_map with boost::hash<uuid> key: dbf8440f-089a-472a-aee4-ebf1bc6446ea | val: v4 random key: 550e8400-e29b-41d4-a716-446655440000 | val: parsed string uuid ---------------------------------------- 9. modify raw bytes via data() modified uuid: ffaa440f-089a-472a-aee4-ebf1bc6446ea raw bytes: ff aa 44 0f 08 9a 47 2a ae e4 eb f1 bc 64 46 ea ---------------------------------------- 10. binary serialize & restore original: dbf8440f-089a-472a-aee4-ebf1bc6446ea restored: dbf8440f-089a-472a-aee4-ebf1bc6446ea equal: true d:\user\01417804\桌面\新建文件夹\project1\x64\debug\project1.exe (进程 76000)已退出,代码为 0 (0x0)。 要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。 按任意键关闭此窗口. . .

到此这篇关于c++ boost::uuid 详解:基于最新版本 boost 的全面指南的文章就介绍到这了,更多相关c++ boost::uuid 内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论