1. C++模板与泛型编程基础
C++模板是泛型编程的核心工具,它允许我们编写与数据类型无关的代码。模板就像是一个蓝图,编译器会根据实际使用的数据类型生成具体的代码。这种机制极大地提高了代码的复用性,让我们能够用同一套逻辑处理不同类型的数据。
在C++中,模板分为函数模板和类模板两种。函数模板允许我们定义通用的函数,而类模板则用于创建通用的类。模板的使用场景非常广泛,特别是在需要处理多种数据类型的容器类(如vector、list等)和算法(如sort、find等)中。
提示:模板代码只有在被实际使用时才会被编译器实例化,这意味着模板代码中的错误可能要到实际使用时才会被发现。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 栈的两种实现方式对比
2.1 手动管理内存的栈实现
手动管理内存的栈实现是最基础的方式,它直接使用动态数组来存储数据。这种实现方式需要开发者自己处理内存分配和释放,虽然灵活性高,但也容易出错。
cpp复制template <typename T>
class Stack {
private:
T* data; // 存储数据的数组
size_t capacity;// 栈的容量
size_t top; // 栈顶指针
public:
Stack(size_t initialCapacity = 10)
: capacity(initialCapacity), top(0) {
data = new T[capacity];
}
~Stack() {
delete[] data;
}
void push(const T& value) {
if (top == capacity) {
// 扩容逻辑
resize(capacity * 2);
}
data[top++] = value;
}
T pop() {
if (empty()) {
throw std::out_of_range("Stack is empty");
}
return data[--top];
}
// 其他成员函数...
};
这种实现方式的主要优点是性能高,因为直接操作内存,没有额外的抽象层。但缺点也很明显:需要手动处理内存管理,容易造成内存泄漏或越界访问。
2.2 容器适配器模式的栈实现
容器适配器模式是更现代、更安全的实现方式。它利用已有的容器(如vector、deque或list)作为底层存储,栈只需要提供符合栈特性的接口即可。
cpp复制template <typename T, typename Container = std::deque<T>>
class Stack {
private:
Container c; // 底层容器
public:
void push(const T& value) {
c.push_back(value);
}
T pop() {
if (empty()) {
throw std::out_of_range("Stack is empty");
}
T value = c.back();
c.pop_back();
return value;
}
bool empty() const {
return c.empty();
}
// 其他成员函数...
};
这种实现方式的优点非常明显:
- 代码简洁,不需要处理复杂的内存管理
- 可以利用底层容器的优化(如vector的内存连续特性)
- 更安全,减少了手动管理内存带来的风险
- 灵活性高,可以轻松更换底层容器
注意:虽然默认使用deque作为底层容器,但在特定场景下选择vector或list可能更合适。例如,如果需要频繁的随机访问,vector可能更好;如果需要频繁的中间插入删除,list可能更优。
3. 栈的核心操作实现细节
3.1 压栈(push)操作
压栈操作是将元素添加到栈顶的过程。在容器适配器实现中,这通常对应于底层容器的push_back操作。
cpp复制void push(const T& value) {
c.push_back(value);
}
对于手动管理内存的实现,压栈操作需要更多考虑:
- 检查容量是否足够
- 必要时进行扩容
- 将元素放入正确位置
- 更新栈顶指针
cpp复制void push(const T& value) {
if (top == capacity) {
resize(capacit
