目录
- 概述
- 自动类型推断机制
- 所有序列化类型总览
- 各类型详细说明
- kBytesType — 原始字节直传
- kProtoType — Protobuf 值类型
- kProtoPtrType — Protobuf 指针类型
- kFlatTableType — FlatBuffers NativeTable
- kFlatPtrType — FlatBuffers 表指针(零拷贝读)
- kFlatBuilderType — FlatBuffers Builder
- kCdrType — FastDDS CDR 编码
- kStandardType — POD 值类型
- kStandardPtrType — POD 指针类型(零拷贝)
- kStringType — std::string
- kCharsType — C 字符串
- kStreamType — 流序列化类型
- kCustomType — 自定义序列化器
- kDynamicType — 动态类型
- 自定义序列化器实现
- Bytes 类详细介绍
- Protobuf 集成
- FlatBuffers 集成
- 性能对比
- 常见错误和避坑指南
概述
VLink 序列化系统基于 **编译期类型推断**,通过 constexpr if 链在编译时确定每种消息类型应使用的编解码器。 应用层代码几乎不需要直接调用序列化 API,框架在 publish()、listen()、invoke()、set()、get() 等接口内部自动完成序列化和反序列化。
序列化推断流程
类型映射总览
序列化类型映射
关键设计原则:
- 所有类型检测和分派均在编译期完成,无虚函数、无运行时类型判断。
- 不支持的类型(kUnknownType)在构造 Publisher/Subscriber/Setter/Getter/Client/Server 时触发 static_assert 编译错误,第一时间暴露问题。
- 同一套 API(publish()、set() 等)对所有序列化类型透明,切换序列化方式只需更换消息类型,无需修改通信代码。
相关文档:
自动类型推断机制
Serializer::get_type_of<T>() 通过以下优先级链依次检测:
T == Bytes -> kBytesType
T 有 is_vlink_dynamic_data() -> kDynamicType
T 有 serialize(Cdr&)/deserialize(Cdr&) -> kCdrType
T 有 SerializeToArray()/ParseFromArray() -> kProtoType
T* 指向有上述方法的消息 -> kProtoPtrType
T 继承 flatbuffers::NativeTable -> kFlatTableType
T* 指向 flatbuffers::Table -> kFlatPtrType
T 有 fbb_ 成员 + Finish() -> kFlatBuilderType
T 有 operator>>(Bytes&)/operator<<(const Bytes&) -> kCustomType
T == std::string -> kStringType
T 可由 std::string 构造(非 string)-> kCharsType
T 是 trivial + standard_layout -> kStandardType
T* 指向 trivial + standard_layout -> kStandardPtrType
T 支持 std::stringstream << 和 >> -> kStreamType
否则 -> kUnknownType(编译报错)
示例:编译期类型查询
constexpr Type get_type_of() noexcept
Deduces the Type enumerator for T at compile time.
定义 serializer-inl.h:160
@ kStandardType
Trivial standard-layout struct (POD value).
定义 serializer.h:137
@ kStringType
std::string – UTF-8 text.
定义 serializer.h:134
constexpr bool is_supported(Type type) noexcept
Returns true when type identifies a supported serializer.
定义 serializer-inl.h:157
Compile-time type-detection and serialisation utilities for VLink messages.
Serializer 核心函数
| 函数 | 说明 |
| Serializer::get_type_of<T>() | 编译期返回 T 对应的 Serializer::Type 枚举值 |
| Serializer::is_supported(Type) | 判断该类型枚举是否受支持(仅 kUnknownType 返回 false) |
| Serializer::serialize(src, des) | 将 src 序列化到 Bytes des,返回 bool |
| Serializer::deserialize(src, des) | 将 Bytes src 反序列化到 des,返回 bool |
| Serializer::convert<SrcT, DesT>(src, des) | 在两种类型之间转换(至少一端必须是 Bytes),返回 bool |
| Serializer::get_serialized_type<T>() | 返回 T 的序列化类型名称字符串(如 Protobuf fully-qualified name) |
| Serializer::get_serialized_size(src) | 返回 src 序列化后的字节大小;大小不可预知时返回 0 |
所有序列化类型总览
| 类型常量 | 触发条件 | 说明 | 依赖库 |
| kBytesType | T == Bytes | 原始字节直传,零拷贝 | 无 |
| kDynamicType | 有 is_vlink_dynamic_data() 成员 | 动态类型,运行时字段定义 | 无 |
| kCdrType | 有 serialize(Cdr&) 和 deserialize(Cdr&) | FastDDS CDR 编码,RTPS 标准 | eProsima FastCDR |
| kProtoType | 有 SerializeToArray() 和 ParseFromArray() | Protobuf 值类型 | protobuf |
| kProtoPtrType | 指向有上述方法的消息的指针 | Protobuf 指针(Arena 管理) | protobuf |
| kFlatTableType | 继承 flatbuffers::NativeTable | FlatBuffers Object API | flatbuffers |
| kFlatPtrType | 指向 flatbuffers::Table 子类的指针 | FlatBuffers 零拷贝读 | flatbuffers |
| kFlatBuilderType | 有 fbb_ 成员 + Finish() | FlatBuffers Builder 模式 | flatbuffers |
| kCustomType | 有 operator>>(Bytes&) 和 operator<<(const Bytes&) | 用户自定义编解码器 | 无 |
| kStringType | T == std::string | UTF-8 字符串 | 无 |
| kCharsType | 可由 std::string 构造(但不是 std::string) | C 字符串字面量 / char* | 无 |
| kStreamType | 支持 std::stringstream 的 << 和 >>(双向流) | 流式文本编码 | 无 |
| kStandardType | std::is_trivial_v && std::is_standard_layout_v(非指针) | POD 结构体,直接内存拷贝 | 无 |
| kStandardPtrType | 指向 trivial + standard_layout 类型的指针 | POD 指针,零拷贝 | 无 |
Serializer::Type(include/vlink/serializer.h:123-139)共 14 个有效枚举(不含 kUnknownType = 0)。kCustomType 的枚举值为 3,但在 get_type_of<T>() 的 if constexpr 链中优先级低于 CDR / Protobuf / FlatBuffers —— 枚举值顺序不等于检测顺序。
各类型详细说明
kBytesType — 原始字节直传
触发条件: T == vlink::Bytes
Bytes 是 VLink 的原生字节容器。发布 Bytes 类型消息时,序列化层直接传递字节缓冲区,无任何额外编解码开销。这是最底层、最灵活的通信方式,适合自定义协议或透明代理场景。
std::memcpy(buf.data(), payload, 256);
pub.publish(buf);
sub.listen([](
const Bytes& msg) {
});
Versatile 128-byte byte buffer with SBO, five ownership modes and compression helpers.
定义 bytes.h:113
size_t size() const noexcept
Returns the number of usable bytes (excluding the prefix offset region).
定义 bytes.h:868
uint8_t * data() noexcept
Returns a pointer to the start of the user data region (after the prefix offset).
定义 bytes.h:860
static Bytes create(size_t size, uint8_t offset=0) noexcept
Creates an owned Bytes buffer of the given size.
Type-safe publisher for the VLink event communication model.
定义 publisher.h:102
Type-safe subscriber for the VLink event communication model.
定义 subscriber.h:110
kProtoType — Protobuf 值类型
触发条件: T 具有 SerializeToArray() 和 ParseFromArray() 方法(通常继承自 google::protobuf::MessageLite)
Protobuf 是最常用的序列化方式,适合跨语言、跨平台的消息定义。VLink 使用 Protobuf 的二进制格式,通过 SerializeToArray() / ParseFromArray() 进行编解码。
#include "my_message.pb.h"
MyProtoMsg msg;
msg.set_id(42);
msg.set_name("hello");
pub.publish(msg);
sub.listen([](const MyProtoMsg& m) {
std::cout << "id=" << m.id() << " name=" << m.name() << std::endl;
});
kProtoPtrType — Protobuf 指针类型
触发条件: T 是指向 Protobuf 消息的原始指针(如 MyProtoMsg*)
适合 Arena 分配模式,避免频繁的 new/delete 开销。VLink 通过指针取值后再序列化。
MyProtoMsg* msg = google::protobuf::Arena::CreateMessage<MyProtoMsg>(&arena);
msg->set_id(1);
pub.publish(msg);
kFlatTableType — FlatBuffers NativeTable
触发条件: T(或 shared_ptr<T> 中的 T)继承 flatbuffers::NativeTable
FlatBuffers Object API 生成的 *T 类(Native Table)。序列化时调用 Pack() 将其打包到 FlatBufferBuilder,反序列化时调用 UnPack()。
#include "my_message_generated.h"
MyMessageT msg;
msg.value = 42;
msg.name = "hello";
pub.publish(msg);
sub.listen([](const MyMessageT& m) {
std::cout << m.value << " " << m.name << std::endl;
});
kFlatPtrType — FlatBuffers 表指针(零拷贝读)
触发条件: T 是指向 flatbuffers::Table 子类的指针(如 const MyMessage*)
零拷贝读取 FlatBuffers 原始缓冲区,无需反序列化到中间对象,访问速度极快。指针直接指向接收缓冲区内的 FlatBuffers 表,生命期与底层 Bytes 一致。
sub.listen([](const MyMessage* m) {
if (m) {
std::cout << m->value() << std::endl;
}
});
kFlatBuilderType — FlatBuffers Builder
触发条件: T 有 fbb_ 成员(FlatBufferBuilder)且有 Finish() 方法
VLink 检测到消息对象持有 FlatBufferBuilder 时,在序列化时直接调用 Finish() 并取出缓冲区。
struct MyFlatMsg {
void Build(int val) {
auto offset = CreateMyMessage(fbb_, val);
}
};
MyFlatMsg msg;
msg.Build(99);
pub.publish(msg);
void Finish() const
定义 serializer-inl.h:132
kCdrType — FastDDS CDR 编码
触发条件: T 有 serialize(eprosima::fastcdr::Cdr&) 和 deserialize(eprosima::fastcdr::Cdr&) 方法,或类名包含 VLINK_FASTDDS_IDL_PREFIX 前缀
CDR(Common Data Representation)是 DDS 标准的二进制格式,由 FastCDR 库实现。通常用于从 IDL 文件自动生成的消息类型。CDR 类型在 dds:// 传输中有特殊快速路径优化(指针直传,无额外字节拷贝)。
#include "MyMessage.h"
#include "MyMessagePubSubTypes.h"
vlink::DdsConf::register_topic<MyMessagePubSubType>("my_topic");
MyMessage msg;
msg.value(42);
pub.publish(msg);
kStandardType — POD 值类型
触发条件: std::is_trivial_v<T> && std::is_standard_layout_v<T>,且 T 不是指针
对于简单的 C 风格结构体(Plain Old Data),VLink 直接进行 sizeof(T) 字节的内存拷贝,无任何编解码开销,是**速度最快**的序列化方式(除零拷贝外)。
struct SensorData {
float temperature;
float humidity;
uint64_t timestamp_us;
};
static_assert(std::is_trivial_v<SensorData>);
static_assert(std::is_standard_layout_v<SensorData>);
SensorData data{25.6f, 60.2f, get_timestamp()};
pub.publish(data);
sub.listen([](const SensorData& d) {
process(d.temperature, d.humidity);
});
注意: POD 类型不包含任何版本信息,结构体字段顺序、大小必须在发布端和订阅端完全一致,否则数据解析错误。不适合跨机器/跨架构的不同字节序场景。
kStandardPtrType — POD 指针类型(零拷贝)
触发条件: T 是指向 trivial + standard_layout 类型的指针
零拷贝 POD,指针被重解释后直接传递,无内存拷贝,适用于大型 POD 结构体(如相机帧、点云)的进程内或共享内存通信。
struct LargeFrame {
uint8_t pixels[1920 * 1080 * 3];
uint64_t timestamp;
};
LargeFrame* frame = get_shm_buffer();
pub.publish(frame);
sub.listen([](const LargeFrame* f) {
if (f) {
display_frame(f->pixels);
}
});
kStringType — std::string
触发条件: T == std::string
UTF-8 字符串,内容直接复制到 Bytes 缓冲区,反序列化时从缓冲区重建 std::string。
pub.publish("System started successfully");
sub.listen([](const std::string& msg) {
std::cout << msg << std::endl;
});
kCharsType — C 字符串
触发条件: 可由 std::string 构造(但不是 std::string),如 const char*
C 字符串字面量或 char* 类型。发布时转为 std::string 再序列化,接收端反序列化为 std::string。
pub.publish("hello from C string");
kStreamType — 流序列化类型
触发条件: T 支持 std::stringstream 的 operator<< 和 operator>>(双向),不是指针类型,且 既不满足 kStandardType 也不满足更高优先级类型 的检测条件。
在类型推断链中(参见 include/vlink/internal/serializer-inl.h 中 get_type_of<T>() 的 if constexpr 链),kStandardType / kStandardPtrType 会在 kStreamType **之前**检测。因此:
- **trivial + standard_layout 的算术类型**(int、double 等)——即使也能通过 stringstream << / >>——仍然会被优先推断为 kStandardType,走 memcpy 二进制路径。
- 只有**非 trivial 或非 standard_layout**(例如带 std::string 成员、带虚函数、带非 POD 成员),但额外实现了 stringstream 双向流的类型,才会落入 kStreamType(文本编码)。
struct MyPod {
float x, y, z;
};
struct MyStreamMsg {
std::string name;
int x;
friend std::ostream& operator<<(std::ostream& os, const MyStreamMsg& m) {
return os << m.name << ' ' << m.x;
}
friend std::istream& operator>>(std::istream& is, MyStreamMsg& m) {
return is >> m.name >> m.x;
}
};
@ kStreamType
Stream-serialisable via operator<<(std::stringstream).
定义 serializer.h:136
kCustomType — 自定义序列化器
触发条件: T 有 operator>>(vlink::Bytes&) 和 operator<<(const vlink::Bytes&) 方法
用户完全控制序列化逻辑,适合:
- 历史遗留的私有二进制协议
- 需要特殊压缩或加密处理的场景
- 不依赖任何第三方序列化库的场景
详见 自定义序列化器实现 章节。
kDynamicType — 动态类型
触发条件: T 有 is_vlink_dynamic_data() 成员函数
动态类型允许在运行时定义字段结构,无需在编译期固定消息格式。适合调试工具、监控系统、协议桥接等场景。通常通过 VLink 的 DynamicData 类使用。
msg["speed"] = 80.0f;
msg["gear"] = 3;
pub.publish(msg);
Runtime-typed container that serializes any VLink-compatible message type.
定义 dynamic_data.h:87
Type-erased data container for runtime serialisation and deserialisation.
自定义序列化器实现
实现自定义序列化器只需在类型上重载两个运算符:
完整示例
#include <cstring>
struct MyCustomProtocol {
uint32_t magic{0xDEADBEEF};
uint16_t cmd{0};
std::vector<uint8_t> payload;
void operator>>(vlink::Bytes& out) const {
size_t total = sizeof(magic) + sizeof(cmd) + sizeof(uint32_t) + payload.size();
uint8_t* ptr = out.
data();
std::memcpy(ptr, &magic, sizeof(magic)); ptr += sizeof(magic);
std::memcpy(ptr, &cmd, sizeof(cmd)); ptr += sizeof(cmd);
uint32_t payload_size = static_cast<uint32_t>(payload.size());
std::memcpy(ptr, &payload_size, sizeof(payload_size)); ptr += sizeof(payload_size);
std::memcpy(ptr, payload.data(), payload.size());
}
const uint8_t* ptr = in.
data();
std::memcpy(&magic, ptr, sizeof(magic)); ptr += sizeof(magic);
std::memcpy(&cmd, ptr, sizeof(cmd)); ptr += sizeof(cmd);
uint32_t payload_size = 0;
std::memcpy(&payload_size, ptr, sizeof(payload_size)); ptr += sizeof(payload_size);
payload.assign(ptr, ptr + payload_size);
}
};
MyCustomProtocol msg;
msg.cmd = 0x01;
msg.payload = {0xAA, 0xBB, 0xCC};
pub.publish(msg);
sub.listen([](const MyCustomProtocol& m) {
std::cout << "cmd=0x" << std::hex << m.cmd << std::endl;
});
@ kCustomType
User-defined via operator>>(Bytes&) / operator<<(const Bytes&).
定义 serializer.h:127
VLINK_EXPORT std::ostream & operator<<(std::ostream &ostream, const BasePtr &status) noexcept
Writes the human-readable description of status to ostream.
注意事项
- operator>> 中必须确保 out 有足够大小,使用 Bytes::create(size) 分配。
- operator<< 不应假设 in.size() 固定,要做合法性检查。
- 两端的序列化/反序列化逻辑必须字节对齐,注意大小端问题。
- 若消息大小可变,在 operator>> 中动态计算所需字节数后再分配。
Bytes 类详细介绍
vlink::Bytes 是 VLink 序列化系统的底层数据载体,所有序列化后的消息都以 Bytes 形式在传输层流动。
设计特点
- **固定对象大小**:对象自身始终为 128 字节(96 字节内联栈缓冲 + 元数据)。
- **小缓冲优化(SBO)**:不超过 96 字节的数据直接存储在对象内,零堆分配。
- **内存池支持**:Linux 下可启用 pmr::synchronized_pool_resource,减少堆分配开销。
- **五种所有权模式**:
| 工厂方法 | 是否拥有内存 | 拷贝行为 | 典型用途 |
| Bytes::create(size) | 是 | 深拷贝 | 普通分配 |
| Bytes::shallow_copy(ptr, size) | 否 | 指针别名 | 零拷贝包装外部缓冲区 |
| Bytes::deep_copy(ptr, size) | 是 | 深拷贝 | 安全拷贝外部缓冲区 |
| Bytes::loan_internal(ptr, size) | 否(借用) | 指针别名 | Iceoryx 零拷贝 Chunk |
| Bytes::shallow_copy_ptr(ptr) | 否 | 指针别名 | 携带不透明指针(size == 0) |
核心 API
uint8_t* p = buf.data();
uint8_t* rp = buf.real_data();
size_t sz = buf.size();
size_t rsz = buf.real_size();
size_t cap = buf.capacity();
bool owned = buf.is_owner();
bool loaned = buf.is_loaned();
bool empty = buf.empty();
buf[0] = 0xFF;
buf.resize(2048);
buf.shrink_to(512);
buf.clear();
std::string to_str = buf.to_string();
std::string_view sv = buf.to_string_view();
void* ptr = get_some_ptr();
auto* recovered = bytes_ptr.to_ptr<MyStruct>();
static Bytes shallow_copy_ptr(void *data) noexcept
Wraps an opaque pointer without associating a byte size.
static Bytes shallow_copy(uint8_t *data, size_t size) noexcept
Creates a non-owning Bytes alias pointing to an external mutable buffer.
static Bytes from_string(const std::string &str, uint8_t offset=0) noexcept
Constructs a Bytes buffer from a std::string by deep-copying its contents.
static Bytes deep_copy(uint8_t *data, size_t size, uint8_t offset=0) noexcept
Creates an owned deep copy of an external mutable buffer.
内存池
static void init_memory_pool() noexcept
Initialises the global thread-safe memory pool for Bytes allocations.
static void release_memory_pool() noexcept
Releases the global memory pool and returns its memory to the OS.
工具方法
}
bool ok = false;
static Bytes reverse_order(const Bytes &target) noexcept
Returns a new Bytes object with the byte order of target reversed.
static Bytes compress_data(const uint8_t *data, size_t size, bool high_ratio=false) noexcept
Compresses a raw byte buffer using the LZAV algorithm.
static Bytes uncompress_data(const uint8_t *data, size_t size, bool check_valid=true) noexcept
Decompresses a LZAV-compressed Bytes buffer.
static bool is_compress_data(const uint8_t *data, size_t size) noexcept
Checks whether a raw byte buffer contains LZAV-compressed VLink data.
static Bytes decode_from_base64(const std::string &target) noexcept
Decodes a Base-64 ASCII string into a Bytes buffer.
static std::string encode_to_base64(const Bytes &target) noexcept
Encodes a Bytes buffer as a standard Base-64 ASCII string.
static constexpr bool is_little_endian() noexcept
Returns true if the platform uses little-endian byte order.
定义 bytes.h:907
static Bytes from_user_input(const std::string &str, bool *ok=nullptr) noexcept
Parses a user-provided hex or binary string literal into a Bytes buffer.
static uint32_t get_crc_32(const Bytes &target) noexcept
Computes the CRC-32 checksum of a Bytes buffer.
static std::string convert_to_hex_str(const uint8_t *value, size_t size) noexcept
Converts a raw byte array to an uppercase hex string with spaces.
static constexpr bool is_big_endian() noexcept
Returns true if the platform uses big-endian byte order.
定义 bytes.h:918
偏移区(Offset)机制
Bytes 支持在数据前预留头部空间,传输层可在原地写入协议头,避免重新分配:
buf.data();
buf.size();
buf.real_data();
buf.offset();
Protobuf 集成
Protobuf / FlatBuffers 的 CMake 集成配置请参阅 构建指南 第 1.6 节。
使用示例
// my_message.proto
syntax = "proto3";
package example;
message VehicleState {
float speed = 1;
int32 gear = 2;
bool engine_on = 3;
string vin = 4;
}
#include "my_message.pb.h"
example::VehicleState state;
state.set_speed(80.0f);
state.set_gear(3);
state.set_engine_on(true);
state.set_vin("LVHB1234567890000");
pub.publish(state);
sub.listen([](const example::VehicleState& s) {
std::cout << "speed=" << s.speed() << " gear=" << s.gear() << std::endl;
});
Protobuf Arena 加速(kProtoPtrType)
google::protobuf::ArenaOptions options;
options.initial_block_size = 4096;
example::VehicleState* state = google::protobuf::Arena::CreateMessage<example::VehicleState>(&arena);
state->set_speed(80.0f);
pub.publish(state);
FlatBuffers 集成
Protobuf / FlatBuffers 的 CMake 集成配置请参阅 构建指南 第 1.6 节。
Schema 示例
// my_message.fbs
namespace example;
table VehicleState {
speed: float;
gear: int;
engine_on: bool;
vin: string;
}
root_type VehicleState;
使用 Object API(kFlatTableType)
#include "my_message_generated.h"
example::VehicleStateT state;
state.speed = 80.0f;
state.gear = 3;
state.engine_on = true;
state.vin = "LVHB1234567890000";
pub.publish(state);
sub.listen([](const example::VehicleStateT& s) {
std::cout << "speed=" << s.speed << std::endl;
});
使用零拷贝指针(kFlatPtrType)
sub.listen([](const example::VehicleState* s) {
if (s) {
std::cout << "speed=" << s->speed() << std::endl;
}
});
性能对比
以下为各序列化方式在不同维度的对比(相对性能,具体数值依消息大小和硬件而定):
| 序列化类型 | 编解码速度 | 消息大小效率 | 零拷贝 | 跨语言支持 | 版本兼容性 | 推荐场景 |
| kStandardType | 极快 | 极小 | 否 | 否 | 无 | 同架构同结构体 POD,高频数据 |
| kStandardPtrType | 极快 | 极小 | 是 | 否 | 无 | 大型 POD,shm 零拷贝 |
| kBytesType | 极快 | 取决于内容 | 是 | 是 | 无 | 透明代理,原始帧数据 |
| kFlatPtrType | 极快 | 小 | 是 | 否 | 向前兼容 | 高性能只读 FlatBuffers |
| kFlatTableType | 快 | 小 | 否 | 是 | 向前兼容 | 高性能读写 FlatBuffers |
| kFlatBuilderType | 快 | 小 | 否 | 是 | 向前兼容 | 手动构建 FlatBuffers |
| kProtoType | 中等 | 中等(压缩) | 否 | 是(多语言) | 向前向后兼容 | 跨语言,含可选字段的消息 |
| kProtoPtrType | 中等 | 中等 | 否 | 是 | 向前向后兼容 | Arena 模式,减少 new/delete |
| kCustomType | 取决于实现 | 取决于实现 | 否 | 否 | 手动维护 | 私有协议,遗留系统 |
| kStringType | 快 | 取决于内容 | 否 | 是 | N/A | 文本日志,命令字符串 |
| kCdrType | 快 | 中等 | 否 | 是(DDS) | IDL 版本 | DDS 标准互操作,IDL 定义消息 |
总结建议:
- 最高性能(进程内/同机):kStandardType(POD)或 kBytesType + shm://
- 高性能 + 结构化:kFlatTableType(FlatBuffers)
- 跨语言/跨版本:kProtoType(Protobuf)
- DDS 标准互操作:kCdrType(CDR)
- 原始控制/特殊协议:kCustomType
常见错误和避坑指南
1. 编译错误:<ValueT> is not a supported Serializer type
原因: 消息类型不匹配任何已知序列化规则,Serializer::get_type_of<T>() 返回 kUnknownType。
struct BadMsg {
int x;
std::vector<int> data;
};
解决方案:
struct GoodMsg {
int x;
std::vector<int> data;
};
2. POD 类型跨架构字节序问题
struct Timestamp {
uint64_t nanoseconds;
};
3. FlatBuffers 零拷贝指针生命期
const example::VehicleState* captured = nullptr;
sub.listen([&captured](const example::VehicleState* s) {
captured = s;
});
sub.listen([](const example::VehicleState* s) {
float speed = s->speed();
auto obj = s->UnPack();
});
4. Protobuf 序列化失败时的处理
pub.publish(huge_proto_msg);
5. kCdrType 必须注册 TypeSupport
vlink::DdsConf::register_topic<MyMessagePubSubType>("topic");
6. 自定义序列化器中错误的 Bytes 操作
std::memcpy(out.
data(), &x,
sizeof(x));
std::memcpy(out.
data(), &x,
sizeof(x));
}
7. Protobuf 和 FlatBuffers 类型在同一 Topic 混用
相关文档: