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;
}

image

结果解读
释放旧数组前:
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;
}

image

错误解析
执行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;
}

image

错误解析
漏写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; 
执行完第 3 步后: 旧数组的 72 字节内存还在,但没有任何指针指向它(parameters_已经指向新数组,也没有其他指针保存旧数组地址); 程序再也找不到这块内存,既不能访问、也不能用delete[]释放; 操作系统也无法主动回收(因为动态内存是 “程序向系统借的”,系统只能等程序主动归还,或程序退出后统一回收); 这块 72 字节的内存就被 “永久泄漏” 了 —— 只要程序不退出,就一直被占用。
posted @ 2026-01-26 10:12  阳光天气  阅读(0)  评论(0)    收藏  举报