如何为C++容器实现供C代码调用的迭代器包装器?
C++模块的C风格迭代器包装实现方案
问题背景
开发一个供C代码调用的C++模块,模块内部用std::map管理对象(方案需同时兼容std::vector),需要编写C包装器,提供C风格的迭代器接口让C代码遍历对象信息——C代码无法识别STL容器和迭代器,因此需要将STL迭代器封装为C端可使用的不透明类型。
C++原有实现
C++端通过EntityManager模板类管理对象,直接使用STL迭代器遍历:
#include <iostream> #include <map> #include <memory> template <typename T> class EntityManager { public: using EntityMap = std::map<int, std::unique_ptr<T>>; using Iterator = typename EntityMap::const_iterator; void registerEntity(int id, std::unique_ptr<T>&& entity) { entityMap.insert(std::make_pair(id, std::move(entity))); } Iterator begin() const { return entityMap.begin(); } Iterator end() const { return entityMap.end(); } private: EntityMap entityMap; }; // 全局管理器实例 using MyManager = EntityManager<std::string>; MyManager myManager; int main() { myManager.registerEntity(1, std::make_unique<std::string>("I'm number one!")); myManager.registerEntity(2, std::make_unique<std::string>("I'm number two!")); auto it = myManager.begin(); auto itEnd = myManager.end(); for (; it != itEnd; ++it) { std::cout << it->first << ": " << *(it->second) << "\n"; } return 0; }
输出结果:
1: I'm number one! 2: I'm number two!
C端期望接口
C代码需要两种可选的迭代器使用方式:
方式1:堆分配不透明指针
// it 是指向动态内存的不透明指针 my_iterator_t it = my_iterator_create(); for (; !my_iterator_done(it); my_iterator_next(it)) { const my_info_type *res = my_iterator_get_info(it); // 处理对象信息... } my_iterator_release(it); // 释放迭代器内存
方式2:栈分配不透明结构体
// it 是栈上的不透明结构体 my_iterator_t it; my_iterator_init(&it); const my_info_type *res; while ((res = my_iterator_next(&it)) != NULL) { // 处理对象... } // 无需释放,迭代器在栈上
具体实现逻辑
通用准备:C头文件定义
首先编写供C代码包含的头文件,声明不透明类型和接口函数:
#ifndef MY_MODULE_H #define MY_MODULE_H #ifdef __cplusplus extern "C" { #endif // 方式1:堆分配迭代器类型(不透明指针) typedef void* my_iterator_t; // 方式2:栈分配迭代器类型(不透明结构体,需保证内部包装类大小不超过此结构体) typedef struct { char data[64]; // 根据平台调整大小,需容纳C++端的IteratorWrapper } my_stack_iterator_t; // 对象信息结构体,C代码可直接访问字段 typedef struct { int id; const char* value; } my_info_type; // ------------------------------ // 堆分配迭代器接口 // ------------------------------ // 创建迭代器 my_iterator_t my_iterator_create(); // 判断迭代器是否已到末尾 int my_iterator_done(my_iterator_t it); // 获取当前迭代器指向的对象信息 const my_info_type* my_iterator_get_info(my_iterator_t it); // 移动迭代器到下一个元素 void my_iterator_next(my_iterator_t it); // 释放迭代器内存 void my_iterator_release(my_iterator_t it); // ------------------------------ // 栈分配迭代器接口 // ------------------------------ // 初始化栈上的迭代器 void my_stack_iterator_init(my_stack_iterator_t* it); // 获取下一个元素,返回NULL表示遍历结束 const my_info_type* my_stack_iterator_next(my_stack_iterator_t* it); // 辅助函数:注册对象(供C代码调用) void my_register_entity(int id, const char* value); #ifdef __cplusplus } #endif #endif // MY_MODULE_H
C++端包装实现
在C++文件中实现上述接口,核心是用内部结构体包装STL迭代器,对C代码隐藏细节:
#include "my_module.h" #include <map> #include <memory> #include <string> template <typename T> class EntityManager { public: // 切换为std::vector即可兼容vector管理的场景 using EntityContainer = std::map<int, std::unique_ptr<T>>; using Iterator = typename EntityContainer::const_iterator; void registerEntity(int id, std::unique_ptr<T>&& entity) { entityContainer.insert(std::make_pair(id, std::move(entity))); } Iterator begin() const { return entityContainer.begin(); } Iterator end() const { return entityContainer.end(); } private: EntityContainer entityContainer; }; // 全局管理器实例 using MyManager = EntityManager<std::string>; MyManager myManager; // 内部迭代器包装类,对C代码完全透明 struct IteratorWrapper { MyManager::Iterator current; MyManager::Iterator end; my_info_type current_info; // 缓存当前元素信息,避免返回临时指针 }; // 确保栈分配的结构体足够容纳内部包装类 static_assert(sizeof(IteratorWrapper) <= sizeof(my_stack_iterator_t), "IteratorWrapper size exceeds my_stack_iterator_t capacity"); // ------------------------------ // 堆分配迭代器实现 // ------------------------------ extern "C" my_iterator_t my_iterator_create() { auto wrapper = new IteratorWrapper(); wrapper->current = myManager.begin(); wrapper->end = myManager.end(); // 初始化第一个元素的信息(如果存在) if (wrapper->current != wrapper->end) { wrapper->current_info.id = wrapper->current->first; wrapper->current_info.value = wrapper->current->second->c_str(); } return static_cast<my_iterator_t>(wrapper); } extern "C" int my_iterator_done(my_iterator_t it) { if (!it) return 1; auto wrapper = static_cast<IteratorWrapper*>(it); return (wrapper->current == wrapper->end) ? 1 : 0; } extern "C" const my_info_type* my_iterator_get_info(my_iterator_t it) { if (!it || my_iterator_done(it)) return nullptr; auto wrapper = static_cast<IteratorWrapper*>(it); return &wrapper->current_info; } extern "C" void my_iterator_next(my_iterator_t it) { if (!it || my_iterator_done(it)) return; auto wrapper = static_cast<IteratorWrapper*>(it); ++wrapper->current; // 更新当前元素信息(如果未到末尾) if (wrapper->current != wrapper->end) { wrapper->current_info.id = wrapper->current->first; wrapper->current_info.value = wrapper->current->second->c_str(); } } extern "C" void my_iterator_release(my_iterator_t it) { if (it) { delete static_cast<IteratorWrapper*>(it); } } // ------------------------------ // 栈分配迭代器实现 // ------------------------------ extern "C" void my_stack_iterator_init(my_stack_iterator_t* it) { if (!it) return; // 原地构造迭代器包装类 auto wrapper = new(it) IteratorWrapper(); wrapper->current = myManager.begin(); wrapper->end = myManager.end(); if (wrapper->current != wrapper->end) { wrapper->current_info.id = wrapper->current->first; wrapper->current_info.value = wrapper->current->second->c_str(); } } extern "C" const my_info_type* my_stack_iterator_next(my_stack_iterator_t* it) { if (!it) return nullptr; auto wrapper = reinterpret_cast<IteratorWrapper*>(it); // 已经到末尾,返回NULL if (wrapper->current == wrapper->end) return nullptr; // 返回当前元素信息,然后移动迭代器 const my_info_type* result = &wrapper->current_info; ++wrapper->current; // 更新下一个元素的信息(如果存在) if (wrapper->current != wrapper->end) { wrapper->current_info.id = wrapper->current->first; wrapper->current_info.value = wrapper->current->second->c_str(); } return result; } // 辅助函数实现 extern "C" void my_register_entity(int id, const char* value) { myManager.registerEntity(id, std::make_unique<std::string>(value)); }
兼容std::vector的修改
只需将EntityManager中的EntityContainer类型替换为std::vector<std::pair<int, std::unique_ptr<T>>>,其余代码无需修改——因为std::vector的迭代器同样支持begin()、end()、++等操作,包装层的逻辑完全通用。
内容的提问来源于stack exchange,提问作者phatpaul
相关产品推荐
相关产品推荐

