C++ 动态数组管理
点击查看代码
#include<iostream>
using namespace std;
int main() {
//模拟BALProblem的核心逻辑:角轴数组->四元数数组
//1.初始化旧数组(角轴格式:假设1个相机,9维参数)
int old_size = 9;//9*1个相机+0个点(简化)
double* parameters_ = new double[old_size] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
cout << "初始状态:" << endl;
cout << "旧数组地址(parameters_):" << parameters_ << endl;
cout << "旧数组前3个值(角轴):" << parameters_[0] << "," << parameters_[1] << "," << parameters_[2] << endl;
//2.分配新数组(四元数格式:1个相机,10维参数)
int new_size = 10;
double* quaternion_parameters = new double[new_size];
cout << "\n分配新数组后: " << endl;
cout << "新数组地址(quaternion_parameters): " << quaternion_parameters << endl;
//3.模拟转换:角轴(3维)转四元数(4维),拷贝剩余6维
//简化:四元数前4位设为10,20,30,40,剩余6位拷贝旧数组的4-9位
quaternion_parameters[0] = 10.0; quaternion_parameters[1] = 20.0;
quaternion_parameters[2] = 30.0; quaternion_parameters[3] = 30.0;
for (int j = 4; j < 10; j++) {
quaternion_parameters[j] = parameters_[j - 1];//拷贝旧数组的4-9位(索引3-8)
}
//4.核心操作:释放旧数组,切换到新数组
cout << "\n执行替换操作:" << endl;
delete[] parameters_;//释放旧内存
cout << "释放旧数组后,parameters_(野指针):" << parameters_ << endl;//地址还在,但内存不可用
parameters_ = quaternion_parameters;
cout << "parameters_ = quaternion_parameter重新赋值后parameters_地址" << parameters_ << endl;
//5.验证:访问新数组(此时parameters_已接管新数组)
cout << "\n验证新数组(通过parameters_访问)" << endl;
cout << "四元数前4位:" << parameters_[0] << "," << parameters_[1] << "," << parameters_[2] << "," << parameters_[3] << endl;
cout << "平移第1位" << parameters_[4] << endl;//对应旧数组的4.0
//6.最终释放新数组(避免内存泄漏)
delete[] parameters_;
return 0;
}

结果解读
释放旧数组前:
parameters_指向000002A2398DAC10(旧数组),quaternion_parameters指向000002A2398D5B00(新数组);
两个数组都占用内存,旧数组存角轴参数,新数组存四元数参数。
执行delete[] parameters_;后:
000002A2398DAC10的内存被操作系统回收,不能再访问(访问会崩溃);
parameters_仍保留000002A2398DAC10这个地址,但变成「野指针」(无效)。
执行parameters_ = quaternion_parameters;后:
parameters_的地址变成000002A2398D5B00,和新数组地址一致;
后续通过parameters_访问的都是新数组的四元数参数,旧数组已彻底 “退场”。
反例 1:顺序反了(先指向新数组,再释放)
这个错误的核心是:先把parameters_指向新数组,再执行delete[],导致新数组被误释放,旧数组内存泄漏,后续访问parameters_会触发未定义行为(崩溃)
点击查看代码
#include <iostream>
using namespace std;
int main() {
// 1. 初始化旧数组(角轴格式:9维)
int old_size = 9;
double* parameters_ = new double[old_size] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
cout << "旧数组地址:" << parameters_ << endl;
// 2. 分配新数组(四元数格式:10维)
int new_size = 10;
double* quaternion_parameters = new double[new_size] {10.0, 20.0, 30.0, 40.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
cout << "新数组地址:" << quaternion_parameters << endl;
// ===== 错误操作:先指向新数组,再释放 =====
parameters_ = quaternion_parameters; // 先让parameters_指向新数组
delete[] parameters_; // 释放的是新数组!旧数组内存泄漏
// 3. 尝试访问parameters_(此时已指向被释放的新数组,野指针)
cout << "\n尝试访问新数组:" << endl;
// 以下代码会触发崩溃/乱码(未定义行为)
cout << "四元数第1位:" << parameters_[0] << endl;
// 4. 最终释放(无意义,新数组已被释放,旧数组永远泄漏)
return 0;
}

错误解析
执行parameters_ = quaternion_parameters后,parameters_和quaternion_parameters都指向新数组的内存地址;
执行delete[] parameters_时,释放的是新数组的内存,而旧数组(9 维)的内存地址已经丢失,永远无法释放(内存泄漏);
后续访问parameters_[0]时,指针指向的是已被操作系统回收的内存,会触发程序崩溃、输出乱码等未定义行为。
反例 2:漏写 delete [](只切换指针,不释放旧内存)
这个错误的核心是:直接让parameters_指向新数组,不释放旧数组的内存,导致旧数组内存永久泄漏,程序运行越久占用内存越多(尤其大规模 BA 场景)。
点击查看代码
#include <iostream>
using namespace std;
int main() {
// 1. 初始化旧数组(角轴格式:9维)
int old_size = 9;
double* parameters_ = new double[old_size] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
cout << "旧数组地址:" << parameters_ << ",占用内存:" << old_size * sizeof(double) << "字节" << endl;
// 2. 分配新数组(四元数格式:10维)
int new_size = 10;
double* quaternion_parameters = new double[new_size] {10.0, 20.0, 30.0, 40.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
cout << "新数组地址:" << quaternion_parameters << ",占用内存:" << new_size * sizeof(double) << "字节" << endl;
// ===== 错误操作:漏写delete[],直接切换指针 =====
// delete[] parameters_; // 关键步骤漏写!
parameters_ = quaternion_parameters; // 只指向新数组,旧数组内存泄漏
// 3. 验证新数组(访问正常,但旧数组内存已丢失)
cout << "\n新数组前4位:" << parameters_[0] << "," << parameters_[1] << "," << parameters_[2] << "," << parameters_[3] << endl;
// 4. 释放新数组(但旧数组的9*8=72字节内存永久泄漏)
delete[] parameters_;
// 查看系统内存(可通过任务管理器观察:程序结束前,内存占用比正确版本多72字节)
cout << "\n程序运行中,旧数组内存已泄漏,无法回收!" << endl;
return 0;
}

错误解析
漏写delete[] parameters_后,旧数组的内存地址被parameters_的新值覆盖,再也无法通过任何指针找到旧数组,操作系统永远无法回收这部分内存;
单个小数组泄漏影响不大,但在 BA 场景中,若参数数组是百万级维度(9num_cameras_+3num_points_),多次泄漏会快速耗尽系统内存,导致程序卡死;
即使程序结束后操作系统会回收所有内存,内存泄漏在长期运行的程序(如服务器、后台进程)中是致命的。
正确代码对比(回顾)
为了强化记忆,这里给出正确的写法,对比两个反例的错误点:
点击查看代码
#include<iostream>
using namespace std;
int main() {
//模拟BALProblem的核心逻辑:角轴数组->四元数数组
//1.初始化旧数组(角轴格式:假设1个相机,9维参数)
int old_size = 9;//9*1个相机+0个点(简化)
double* parameters_ = new double[old_size] {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
cout << "初始状态:" << endl;
cout << "旧数组地址(parameters_):" << parameters_ << endl;
cout << "旧数组前3个值(角轴):" << parameters_[0] << "," << parameters_[1] << "," << parameters_[2] << endl;
//2.分配新数组(四元数格式:1个相机,10维参数)
int new_size = 10;
double* quaternion_parameters = new double[new_size];
cout << "\n分配新数组后: " << endl;
cout << "新数组地址(quaternion_parameters): " << quaternion_parameters << endl;
//3.模拟转换:角轴(3维)转四元数(4维),拷贝剩余6维
//简化:四元数前4位设为10,20,30,40,剩余6位拷贝旧数组的4-9位
quaternion_parameters[0] = 10.0; quaternion_parameters[1] = 20.0;
quaternion_parameters[2] = 30.0; quaternion_parameters[3] = 30.0;
for (int j = 4; j < 10; j++) {
quaternion_parameters[j] = parameters_[j - 1];//拷贝旧数组的4-9位(索引3-8)
}
//4.核心操作:释放旧数组,切换到新数组
cout << "\n执行替换操作:" << endl;
delete[] parameters_;//释放旧内存
cout << "释放旧数组后,parameters_(野指针):" << parameters_ << endl;//地址还在,但内存不可用
parameters_ = quaternion_parameters;
cout << "parameters_ = quaternion_parameter重新赋值后parameters_地址" << parameters_ << endl;
//5.验证:访问新数组(此时parameters_已接管新数组)
cout << "\n验证新数组(通过parameters_访问)" << endl;
cout << "四元数前4位:" << parameters_[0] << "," << parameters_[1] << "," << parameters_[2] << "," << parameters_[3] << endl;
cout << "平移第1位" << parameters_[4] << endl;//对应旧数组的4.0
//6.最终释放新数组(避免内存泄漏)
delete[] parameters_;
return 0;
}
总结
顺序反的核心问题:误释放新数组,旧数组泄漏,后续访问野指针导致程序崩溃;
漏写 delete [] 的核心问题:旧数组内存永久泄漏,长期运行会耗尽系统资源;
正确原则:动态数组替换时,必须「先释放旧内存 → 再指向新内存」,且new[]和delete[]严格配对。
这两个反例是 C++ 新手最容易踩的坑,记住 “先释放、后赋值” 的核心逻辑,再结合智能指针 /vector 等工具,就能彻底避免这类问题。
注:内存泄漏
是程序员通过new/new[]向操作系统申请了动态内存,但后续失去了所有指向这块内存的指针,导致操作系统既收不回内存,程序也无法再使用这块内存,这块内存就变成了 “无人认领的垃圾”,永久占用系统资源。
用之前的反例 2 来具象化理解:
点击查看代码
// 1. 申请旧数组内存(9个double,72字节),parameters_指向它
double* parameters_ = new double[9];
// 2. 申请新数组内存(10个double,80字节)
double* quaternion_parameters = new double[10];
// 3. 漏写delete[],直接让parameters_指向新数组
parameters_ = quaternion_parameters;

浙公网安备 33010602011771号