You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:34:52