C++接口内部内存分配问题设计方案

 更新时间:2026年04月13日 09:06:45   作者:CVer儿  
本文主要介绍了在C++中使用二级指针(**)进行内存分配和数据传递的主要应用场景,结合使用vector和二级指针进行数据传递的方法,感兴趣的朋友跟随小编一起看看吧

1. 为什么要传入“二级指针” (**)?

当你需要 C++ 内部产生一份未知大小的数据,并把数据交还给外部时:

  • 如果你传一级指针 (DataPoints* ptr):C++ 内部执行 ptr = new DataPoints[10]; 时,修改的只是 ptr 这个变量在栈上的局部副本。函数一结束,外部的指针依然是 nullptr,不仅拿不到数据,还会造成内存泄漏。
  • 传入二级指针 (DataPoints** ptr_addr):你传进来的是“外部指针变量的地址”。C++ 内部执行 *ptr_addr = new DataPoints[10]; 时,是直接顺着地址找到了外部的那个指针,把新分配的内存首地址硬塞给它。这样外部就能成功拿到数据了。

2. 必须“C++ 内部分配,并提供内部接口释放”

传入一级指针通常用于以下 三大黄金场景

场景一:只读的数据输入(Input Arrays / Structs)

当需要把大量数据从 C# 传给 C++ 让它进行计算时,绝不会把几十万个坐标点按值(By Value)传进去,而是传首地址(一级指针)。

  • 工作流:C# 在自己的托管堆(或非托管堆)上准备好了一排 DataPoints,然后把**首个元素的地址(一级指针)**传给 C++。C++ 内部只做遍历和读取(Bins[i].DataPoints_x),绝对不会对 Bins 执行 newdelete
  • 总结:用于**“只读”**的大块数据传输。

场景二:调用方预分配内存的高速填充

        这是工业视觉和音视频处理中最高效、最极客的输出模式。 如果 C# 端提前知道计算结果大概有多大(或者结果大小是固定的),那么由 C# 提前申请好内存,传一级指针给 C++ 去“填空”,是比“二级指针内部 new”更快的做法!

举个实际的例子: 假设你的点云重采样后固定是 1200 个点,C# 完全可以自己提前 new double[1200]

C++ 接口设计:

// 传入一级指针 pre_alloc_x 和 pre_alloc_y
void ProcessSingleCloud(double* pre_alloc_x, double* pre_alloc_y, int fixed_len) {
    // C++ 内部绝对不写 new!直接往外部传进来的地址里塞数据
    for(int i=0; i<fixed_len; i++) {
        pre_alloc_x[i] = ...; // 直接填充
        pre_alloc_y[i] = ...;
    }
}

C# 调用方:

// C# 自己分配好内存
double[] out_x = new double[1200];
double[] out_y = new double[1200];
// 传首地址(一级指针)给 C++
ProcessSingleCloud(out_x, out_y, 1200); 
// 调用结束,数据已经在 out_x 里了,完全不需要管释放问题(C# 的 GC 会自动回收)!

优势:彻底干掉了 FreeDataPoints 这步操作!没有任何跨语言释放内存的风险,性能达到绝对的物理极限。

劣势:如果 C++ 计算出来的结果大小是未知的(比如不确定会返回 500 个点还是 800 个点),C# 就无法提前精准分配内存,这时候就只能退回“二级指针内部 new”的方案了。

3 vector结合二级指针

        既然 vector 这么好用(比如不确定最终会匹配出多少个结果时,可以随时 push_back),我们当然要在内部用它。

正确的架构模式是:数据在函数内部完全用 std::vector 装载,但在函数的最后一行,把 vector 里的数据“过继(Copy/Move)”给一个通过 new[] 分配的裸数组。

完美结合 Vector 的代码实现:

void F_FindSimilarXldPoint(..., DataPoints** DataPoints_tf, int* DataPoints_tfCount) {
    // 1. 内部愉快地使用 vector,享受动态扩容的便利
    std::vector<DataPoints> temp_results;
    for (int i = 0; i < batch; ++i) {
        // 假设某些条件不满足,直接 continue,最终数量不确定
        if (/* 匹配失败 */ false) continue; 
        // 构造单个结果
        DataPoints dp;
        dp.DataPoints_Lenth = 1200;
        // 🌟 注意:底层坐标数组必须也是 new 出来的,因为要传给外部
        dp.DataPoints_x = new double[1200];
        dp.DataPoints_y = new double[1200];
        // ... 填充坐标数据 ...
        temp_results.push_back(dp); // 装入 vector
    }
    // ==========================================================
    // 2. 🌟 核心交接仪式 (Transfer Ownership)
    // ==========================================================
    int final_count = temp_results.size();
    *DataPoints_tfCount = final_count;
    if (final_count > 0) {
        // 分配一块干净的裸数组内存
        DataPoints* out_array = new DataPoints[final_count];
        // 浅拷贝:把 vector 里的 DataPoints 结构体(包含里面的 x, y 指针)
        // 逐个复制给 out_array
        for (int i = 0; i < final_count; ++i) {
            out_array[i] = temp_results[i]; 
        }
        // 把裸数组的地址交给二级指针
        *DataPoints_tf = out_array;
    } else {
        *DataPoints_tf = nullptr;
    }
} // <--- 函数结束,temp_results(vector) 被销毁。
  // 但是不用担心!因为 vector 里装的是指针副本,
  // 真正的数据 (new double[] 和 new DataPoints[]) 已经挂在 out_array 上活下来了!

极小开销: 你可能会担心最后的 for 循环复制会慢。其实完全不会!这里发生的是浅拷贝 (Shallow Copy),仅仅是复制了 DataPoints 结构体里的 3 个变量(两个指针,一个 int),并没有复制那 1200 个 double 数据。就算有 1000 个零件,复制 1000 个结构体的时间连 0.01 毫秒都不到。

到此这篇关于C++接口内部内存分配问题设计方案的文章就介绍到这了,更多相关c++接口内部内存分配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C 语言基础之C语言的常见关键字

    C 语言基础之C语言的常见关键字

    C语言中有一些预先定义的字符串,他们本身被赋予了自身的功能。并且我们在定义变量的时候,不能去抢他们的名字来用。他们就是今天的主角:关键字,下面文章将给大家做详细介绍
    2021-09-09
  • 基于Matlab实现BP神经网络交通标志识别

    基于Matlab实现BP神经网络交通标志识别

    道路交通标志用以禁止、警告、指示和限制道路使用者有秩序地使用道路, 保障出行安全.若能自动识别道路交通标志, 则将极大减少道路交通事故的发生。本文将介绍基于Matlab实现BP神经网络交通标志识别,感兴趣的可以学习一下
    2022-01-01
  • 基于C++内存分配、函数调用与返回值的深入分析

    基于C++内存分配、函数调用与返回值的深入分析

    本篇文章是对C++中的内存分配、函数调用与返回值进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C++的虚继承实现示例

    C++的虚继承实现示例

    虚继承是C++中解决多重继承中菱形继承问题的专属机制,通过让共同基类成为虚基类,保证其在最终派生类中仅存在一份实例,消除数据冗余和访问二义性,下面就来介绍一下C++ 虚继承的使用
    2026-02-02
  • 详解socket阻塞与非阻塞,同步与异步、I/O模型

    详解socket阻塞与非阻塞,同步与异步、I/O模型

    这篇文章主要介绍了详解socket阻塞与非阻塞,同步与异步、I/O模型,socket网络编程中的同步,异步,阻塞式,非阻塞式,有何联系与区别,本文将详细讲诉。
    2016-12-12
  • 浅谈关于C语言中#define的副作用

    浅谈关于C语言中#define的副作用

    这篇文章主要介绍了关于C语言中#define的副作用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 在 VSCode 中配置 C++ 开发环境的详细教程

    在 VSCode 中配置 C++ 开发环境的详细教程

    本文详细介绍了如何在Visual Studio Code(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通过这些步骤,你可以快速搭建C++开发环境,实现高效编程,感兴趣的朋友一起看看吧
    2025-01-01
  • C++ 遍历二叉树实例详解

    C++ 遍历二叉树实例详解

    这篇文章主要介绍了C++ 遍历二叉树实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • C语言入门之指针用法教程

    C语言入门之指针用法教程

    这篇文章主要介绍了C语言入门之指针用法教程,主要对C语言中指针的本质及常见用法做了较为通俗易懂的分析,是后续深入学习C语言的基础,需要的朋友可以参考下
    2014-09-09
  • c++中的消息框messagebox()详细介绍及使用方法

    c++中的消息框messagebox()详细介绍及使用方法

    本文将介绍下c++中的messagebox()的使用方法:常用属性/按钮的形式/返回值等等,感兴趣的朋友可以了解下,希望本文可以帮助到你
    2013-02-02

最新评论