传指针前必须确认所有权归属,依据函数命名、参数类型和文档说明判断释放责任;对外暴露c++接口需封装为c兼容形式;const正确性影响线程安全与abi稳定性;多线程下须确保指针生命周期与同步契约一致。

传指针前必须确认所有权归属
API 文档没写清楚时,最容易踩的坑是误以为自己能 free 掉 API 返回的指针。比如 mysql_init(NULL) 返回的 MYSQL* 指针,必须用 mysql_close() 释放,不能直接 delete 或 free();又如 webview_create() 返回的 webview_t,必须配对调用 webview_destroy()。所有权不明确会导致双重释放或内存泄漏。
判断依据有三个:
- 看函数命名:带
_create/_init的,通常要求调用对应_destroy/_close - 看参数是否含
void*或void**:若 API 接收void** out_handle,说明它要帮你分配并移交所有权 - 查返回值文档:MySQL C API 明确写 “The pointer returned by
mysql_init()must be passed tomysql_close()”
避免裸指针跨边界传递
对外暴露 C++ 接口给 Python、Rust 或 C 时,别直接导出 std::string* 或 MyClass*。C ABI 不认识 C++ 类型,调用方可能解引用失败或触发未定义行为。常见错误现象包括访问违规、std::string::length() returned garbage、或 Python 中拿到 NULL 却无报错。
安全做法是封装一层 C 兼容接口:
- 用
const char*替代std::string*,且确保字符串生命周期长于调用方使用时间(例如用static std::string buffer缓存,或让调用方负责malloc+free) - 对复杂对象,导出句柄(
typedef void* my_handle_t),内部用std::shared_ptr管理,再提供my_handle_release(my_handle_t h)显式释放 - 所有异常路径必须保证句柄不泄露:在
try块内完成资源获取,在catch中立即调用释放函数
const 正确性决定能否安全传指针
传 const T* 还是 T*,不只是语义问题,更影响线程安全和 ABI 稳定性。比如 Win32 API 中大量使用 LPCWSTR(即 const wchar_t*),若你传入非 const 指针,编译器可能静默插入 const_cast,导致后续修改引发未定义行为。
关键规则:
- 只读数据 → 强制用
const T*,哪怕 API 声明为T*(只要它真不改) - 输出参数 → 必须用
T*或T**,但需配合文档说明“调用方分配缓冲区,大小至少 X 字节” - 结构体成员含指针时,
const要作用到每一层:const std::vector<:string>* vec</:string>不等于const std::vector<const std::string>* vec</const>,后者才真正禁止修改字符串内容
多线程下指针传递必须加同步契约
当 API 内部缓存了你传入的指针(例如 webview_bind() 注册 JS 回调时传入 C 函数指针),而该 API 又在后台线程调用它,你就必须保证:该指针所指向的数据/对象在整个调用期间有效。常见崩溃场景是主线程已析构对象,后台线程却还在通过悬挂指针访问 this。
可行方案:
- 用
std::shared_ptr包装对象,把std::shared_ptr<t></t>的原始指针传入 API,同时在回调里用weak_ptr.lock()检查是否仍存活 - 禁止传栈对象地址给异步 API:像
int x = 42; api_call(&x)在回调中读*x是未定义行为 - 若 API 不支持弱引用,必须显式约定生命周期:例如 “回调执行完毕后,调用方才能销毁对象”,并在文档中标记
[[nodiscard]]或注释 // Caller retains ownership until on_complete()
实际中最容易被忽略的是:所有权移交和生命周期管理从来不是单靠代码语法能约束的,它依赖文档、命名和调用方与被调用方之间的显式契约。哪怕用了 std::shared_ptr,如果一方提前 .reset(),另一方仍可能拿到空指针——这得靠设计阶段就写死契约,而不是靠运行时防御。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











