C++中已有的动态数组内动态创建元素是否存在合理场景?
为什么需要用
Object** objectArray = new Object*[someSize];这种写法? 首先明确两种数组的核心差异:
Object* objectArray = new Object[someSize];:在堆上分配连续的someSize个Object对象,所有元素内存连续,创建时必须调用Object的默认构造函数。Object** objectArray = new Object*[someSize];:在堆上分配连续的someSize个Object指针,每个指针需手动指向堆上的Object实例(或留空为nullptr),元素实际内存可不连续,且支持用带参构造函数创建每个实例。
这种二级指针数组的写法有不少实际用例:
1. 需用带参数的构造函数初始化元素
如果Object没有默认构造函数,或者需要给每个元素传入不同的初始化参数,new Object[someSize]会直接编译失败——因为new[]默认会调用元素的默认构造函数。而二级指针数组可以逐个调用带参构造:
// 假设Object仅提供带参构造:Object(int val); Object** arr = new Object*[3]; arr[0] = new Object(10); arr[1] = new Object(20); arr[2] = new Object(30);
2. 存储多态类的子类对象
如果Object是基类,你需要在数组中存储不同子类的对象以实现多态,第一种写法的数组会触发切片问题:只能存储Object基类对象,无法保留子类的特性。而二级指针数组存储的是基类指针,可以指向子类对象,完美支持多态:
class Object { public: virtual void print() { cout << "Object\n"; } virtual ~Object() = default; }; class SubObjectA : public Object { public: void print() override { cout << "SubObjectA\n"; } }; class SubObjectB : public Object { public: void print() override { cout << "SubObjectB\n"; } }; // 用二级指针数组存储不同子类实例 Object** arr = new Object*[2]; arr[0] = new SubObjectA(); arr[1] = new SubObjectB(); arr[0]->print(); // 输出SubObjectA arr[1]->print(); // 输出SubObjectB
3. 动态管理元素的存在性或内存
第一种写法的数组元素是固定存在的,内存连续且大小不可变。而二级指针数组更灵活:
- 可以只给需要的索引分配对象,其他指针设为
nullptr,适合稀疏数组场景,节省内存。 - 可以随时销毁某个元素并重新分配,或替换为其他对象,不影响数组其他元素。
4. 避免大对象连续分配的问题
如果Object是体积很大的对象,一次性分配连续的someSize个大对象可能因为堆上没有足够连续内存块而分配失败。二级指针数组可以逐个分配独立的小内存块,更容易分配成功,也能减少连续大内存块带来的内存碎片。
额外提示
现代C++中更推荐用标准库容器(比如std::vector<std::unique_ptr<Object>>)替代手动管理二级指针数组,避免内存泄漏和手动释放的繁琐,但底层逻辑和上述场景一致。
内容的提问来源于stack exchange,提问作者Micah Gant
相关产品推荐
相关产品推荐

