我正在尝试编写一个异常安全的通用堆栈。这是我到目前为止所做的。
#include <iostream>
#include <memory>
#include <exception>
class stk_exception:public exception
{
virtual const char* what() const throw()
{
return "stack underflow";
}
} stk_ex;
template <class T>
struct node
{
T data;
node<T> *next;
};
template <class T>
class stack_generic
{
public:
stack_generic() : _head(nullptr) {
}
void push(T x) {
node<T> *temp(new node<T>());
temp->data = x;
temp->next = _head;
_head = temp;
}
void pop() {
if (_head == nullptr) {
throw stk_ex;
} else {
node<T> *temp = _head;
_head = _head->next;
delete temp;
return;
}
}
T top() {
T x = T();
if (_head == nullptr) {
throw stk_ex;
} else {
return _head->data;
}
}
private:
node<T> *_head;
};
int main()
{
stack_generic<int> s;
s.push(1);
s.push(2);
std::cout << s.top();
s.pop();
std::cout << s.top();
s.pop();
}
我本可以使用STL列表/向量来实现RAII,但我想使用原始指针。因此,当我使用unique_ptr将头指针包装在堆栈中时,它会抛出一个编译错误&#34;没有用于调用unique_ptr,default_delete的匹配函数。这里有什么问题?任何人都可以建议我该怎么做才能使这个类异常安全?谢谢!
编辑: 添加了下溢的异常处理。 定义了单独的top和pop方法
答案 0 :(得分:5)
以下实现应该(几乎)是异常安全的:
void push(T x) {
head = new node<T>{std::move(x), head};
}
T pop(void) {
if (head) {
T result{std::move(head->data)};
auto old = head;
head = head->next;
delete old;
return result;
} else {
cout << "underflow!";
return T{};
}
}
此代码的唯一问题是return result
。通常,此操作可能会抛出异常,在这种情况下,调用者会看到异常,但堆栈仍然会更改。
您可以通过将功能分成两个功能来避免此问题。第一个函数返回top元素,第二个函数删除它。
答案 1 :(得分:2)
最佳做法是使用std::shared_ptr
。您可以像这样实现类:
#include <iostream>
#include <memory>
#include <exception>
template <class T>
class node
{
public:
node(T data, std::shared_ptr<node<T>> next)
: _data(data), _next(next)
{
}
T data() const
{
return _data;
}
std::shared_ptr<node<T>> next() const
{
return _next;
}
private:
T _data;
std::shared_ptr<node<T>> _next;
};
template <class T>
class stack_generic
{
public:
stack_generic()
: _head(nullptr)
{
}
void push(T x)
{
_head = std::make_shared<node<T>>(x, _head);
}
T pop()
{
if (_head == nullptr) {
throw std::underflow_error("underflow");
} else {
std::shared_ptr<node<T>> temp = _head;
_head = _head->next();
return temp->data();
}
}
private:
std::shared_ptr<node<T>> _head;
};
int main()
{
stack_generic<int> s;
s.push(1);
s.push(2);
std::cout << s.pop();
std::cout << s.pop();
}
请注意以下事项:
using namespace std;
是不好的做法。nullptr
而不是NULL
。std::shared_ptr
自动释放数据。