如何在C++中不使用指针或new实现动态数组?
不用手动
new/delete实现自定义动态数组的方案 首先明确:动态数组的底层必然依赖指针管理连续堆内存,完全避开指针做不到,但我们可以借助现代C标准库工具,把裸指针、手动new/delete的操作封装起来,让代码更安全、更符合现代C规范——这也是提升编程水平的关键方向。
下面给你两种可行的改进方案:
方案一:用智能指针管理动态数组
std::unique_ptr<T[]>是标准库专门为动态数组设计的智能指针,它会自动在生命周期结束时释放内存,彻底避免手动写delete[]带来的内存泄漏或double free问题。
修改后的Myvector代码示例:
#include <iostream> #include <memory> // 引入智能指针头文件 template<class T> class Myvector{ private: int size; int capacity; std::unique_ptr<T[]> objects; // 替换裸指针为unique_ptr void add_capacity(){ int newCapacity = capacity * 2 + 1; // 用make_unique创建新数组,自动管理内存 auto newArray = std::make_unique<T[]>(newCapacity); for(int i = 0; i < size; ++i){ newArray[i] = std::move(objects[i]); } capacity = newCapacity; // 交换智能指针,旧数组会被自动释放 objects.swap(newArray); } public: Myvector() : size(0), capacity(1), objects(std::make_unique<T[]>(1)){} void add(T obj){ if(capacity == size){ add_capacity(); } objects[size] = std::move(obj); // 用move减少拷贝开销 size += 1; } // 迭代器逻辑无需修改,智能指针的operator[]返回引用,取地址后仍是指针 class Iterator{ public: T* operator->() { return ptr; } Iterator(T* p) : ptr(p){} Iterator operator++(){ ++ptr; return *this; } bool operator!=(const Iterator& other) const{ return ptr != other.ptr; } const T& operator*() const{ return *ptr; } private: T* ptr; }; Iterator begin() { return Iterator(&objects[0]); } Iterator end() { return Iterator(&objects[size]); } };
方案二:用std::allocator实现高效内存管理
如果想更贴近标准库std::vector的实现逻辑,可以用std::allocator——它把内存分配和对象构造分离,解决了new T[N]会默认构造所有元素的问题(对于无默认构造函数的类型,原代码会直接编译失败),同时完全避开手动new/delete。
修改后的代码示例:
#include <iostream> #include <memory> // 引入allocator头文件 template<class T> class Myvector{ private: int size; int capacity; std::allocator<T> alloc; // 分配器对象 T* objects; // 仍需指针,但内存分配由allocator处理 void add_capacity(){ int newCapacity = capacity * 2 + 1; // 只分配内存,不构造对象 T* newArray = alloc.allocate(newCapacity); // 移动构造现有元素到新内存 for(int i = 0; i < size; ++i){ alloc.construct(newArray + i, std::move(objects[i])); alloc.destroy(objects + i); // 销毁旧内存中的对象 } alloc.deallocate(objects, capacity); // 释放旧内存 objects = newArray; capacity = newCapacity; } public: Myvector() : size(0), capacity(1), objects(alloc.allocate(1)){} // 析构函数需手动销毁所有对象并释放内存 ~Myvector(){ for(int i = 0; i < size; ++i){ alloc.destroy(objects + i); } alloc.deallocate(objects, capacity); } // 禁用拷贝构造和赋值(需支持的话可自行实现深拷贝) Myvector(const Myvector&) = delete; Myvector& operator=(const Myvector&) = delete; // 实现移动构造和赋值,提升性能 Myvector(Myvector&& other) noexcept : size(other.size), capacity(other.capacity), objects(other.objects){ other.size = 0; other.capacity = 0; other.objects = nullptr; } Myvector& operator=(Myvector&& other) noexcept{ if(this != &other){ // 清理当前资源 for(int i = 0; i < size; ++i){ alloc.destroy(objects + i); } alloc.deallocate(objects, capacity); // 转移对方资源 size = other.size; capacity = other.capacity; objects = other.objects; other.size = 0; other.capacity = 0; other.objects = nullptr; } return *this; } void add(T obj){ if(capacity == size){ add_capacity(); } alloc.construct(objects + size, std::move(obj)); // 直接构造新对象 size += 1; } // 迭代器逻辑保留 class Iterator{ public: T* operator->() { return ptr; } Iterator(T* p) : ptr(p){} Iterator operator++(){ ++ptr; return *this; } bool operator!=(const Iterator& other) const{ return ptr != other.ptr; } const T& operator*() const{ return *ptr; } private: T* ptr; }; Iterator begin() { return Iterator(objects); } Iterator end() { return Iterator(objects + size); } };
额外提升建议
- 实现
emplace_back:替代add方法,直接在数组末尾构造对象,避免不必要的拷贝/移动。 - 完善迭代器类型:添加
iterator_category、value_type等类型定义,让迭代器适配标准库算法。 - 添加边界检查:比如实现
operator[]时加入越界检查(用assert或抛出异常)。 - 补充拷贝语义:如果需要支持拷贝,手动实现拷贝构造和赋值函数,完成深拷贝逻辑。
内容的提问来源于stack exchange,提问作者Ode
相关产品推荐
相关产品推荐

