代码:
cpp
#include <iostream>
#include <stdexcept> // 用于 std::out_of_range
class IntStack {
private:
int* _data; // 动态数组指针,指向堆上的内存
size_t _capacity; // 栈的总容量(数组大小)
size_t _top; // 栈顶索引(指向下一个可插入位置,也代表当前元素个数)
// 私有辅助函数:扩容
void resize() {
size_t new_capacity = _capacity * 2;
int* new_data = new int[new_capacity]; // 1. 分配新内存
// 2. 复制旧数据
for (size_t i = 0; i < _top; ++i) {
new_data[i] = _data[i];
}
// 3. 释放旧内存并更新指针
delete[] _data;
_data = new_data;
_capacity = new_capacity;
}
public:
// 1. 构造函数
explicit IntStack(size_t init_size = 10)
: _capacity(init_size), _top(0) {
if (init_size == 0) {
_data = nullptr;
} else {
_data = new int[_capacity];
}
}
// 2. 析构函数 (三法则之一)
~IntStack() {
delete[] _data; // 释放堆内存
}
// 3. 拷贝构造函数 (三法则之一)
IntStack(const IntStack& other)
: _capacity(other._capacity), _top(other._top) {
if (_capacity == 0) {
_data = nullptr;
} else {
_data = new int[_capacity];
for (size_t i = 0; i < _top; ++i) {
_data[i] = other._data[i];
}
}
}
// 4. 赋值运算符 (三法则之一)
IntStack& operator=(const IntStack& other) {
if (this != &other) { // 防止自赋值
// 1. 申请新资源
int* new_data = nullptr;
size_t new_capacity = other._capacity;
if (new_capacity > 0) {
new_data = new int[new_capacity];
for (size_t i = 0; i < other._top; ++i) {
new_data[i] = other._data[i];
}
}
// 2. 释放旧资源
delete[] _data;
// 3. 更新状态
_data = new_data;
_capacity = new_capacity;
_top = other._top;
}
return *this;
}
// 5. 元素个数
size_t size() const {
return _top;
}
// 6. 判空
bool empty() const {
return _top == 0;
}
// 7. 入栈
void push(int value) {
if (_top >= _capacity) {
resize(); // 自动扩容
}
_data[_top++] = value; // 先赋值,再自增
}
// 8. 访问栈顶元素 (不删除)
int& top() {
if (empty()) {
throw std::out_of_range("IntStack top() error: stack is empty");
}
return _data[_top - 1];
}
const int& top() const {
if (empty()) {
throw std::out_of_range("IntStack top() error: stack is empty");
}
return _data[_top - 1];
}
// 9. 出栈 (删除栈顶元素)
void pop() {
if (empty()) {
throw std::out_of_range("IntStack pop() error: stack is empty");
}
--_top;
}
};
该类主要由以下几个核心模块组成,每个模块都有其特定的作用:
1. 私有成员变量 (数据存储)
_data (int*): 这是一个指针,指向堆上分配的连续内存块(动态数组)。它是存储栈中所有元素的物理容器。
_capacity (size_t): 记录 _data 数组的总长度。表示栈最多能存多少个元素而不需要重新申请内存。
_top (size_t): 栈顶指针。这里采用的是"左闭右开"区间逻辑,_top 指向下一个待插入元素的位置 。因此,_top 的值也等于当前栈中元素的个数。
2. 辅助函数 resize()
作用 :当栈满(_top == _capacity)时,自动扩大存储空间。
用处:
- 申请一块两倍于当前容量的新内存。
- 将旧内存中的所有数据逐个复制到新内存。
- 释放旧内存,并让
_data指向新内存
3. 构造函数 IntStack()
作用:初始化对象。
细节 :使用了 explicit 防止隐式类型转换。默认初始容量为 10。如果初始大小为 0,则将指针置空。
4. 析构函数 ~IntStack()
作用:清理资源。
关键点 :必须使用 delete[] 释放构造函数中 new 出来的数组。这是防止内存泄漏的关键。
5. 拷贝控制 (三法则)
为了管理动态内存,必须手动控制拷贝行为:
拷贝构造函数 :当用一个栈初始化另一个栈时调用。它执行深拷贝,即不仅复制指针,还复制指针指向的数据,确保两个栈互不影响。
赋值运算符:当一个栈被赋值给另一个已存在的栈时调用。它需要先释放自己原有的内存,再申请新内存复制数据,并处理自赋值的情况。
6. 核心接口
push(int): 入栈。先检查是否需要扩容,然后将元素放入 _data[_top] 位置,最后 _top 加 1。
pop(): 出栈。仅将 _top 减 1(逻辑上删除),不实际删除数据。
top(): 访问栈顶。返回 _data[_top - 1] 的引用,允许读写。如果栈空则抛出异常。
empty(): 通过判断 _top 是否为 0 来确定栈是否为空。
size(): 返回 _top 的值。
测试代码:
cpp
int main() {
IntStack s;
s.push(10);
s.push(20);
std::cout << "Top: " << s.top() << std::endl; // 输出 20
s.pop();
std::cout << "Size: " << s.size() << std::endl; // 输出 1
return 0;
}