【发布时间】:2020-02-05 18:12:13
【问题描述】:
我正在使用模板实现自定义堆栈。但是我遇到了一个让我质疑内存安全的问题。析构函数在正常使用时工作正常,但在单元测试时会触发堆损坏。特别是在期望抛出异常的测试上。
所有堆栈代码。
#pragma once
#include "StackOverflowException.h"
#include "StackEmptyException.h"
template <class T>
class Stack
{
public:
const static int MAX_SIZE = 1000;
Stack() : m_array(new T[MAX_SIZE]), m_size(0), m_top(0) {};
Stack(const Stack<T>& _other)
{
m_array = new T[MAX_SIZE];
for(auto i = 0; i < _other.size(); ++i)
{
m_array[i] = _other.m_array[i];
}
m_size = _other.size();
m_top = _other.m_top;
}
~Stack()
{
delete[] m_array;
}
void push(T _item)
{
if (m_size + 1 == MAX_SIZE + 1)
{
throw StackOverflowException();
}
m_array[++m_top] = _item;
++m_size;
}
T pop()
{
if(m_top != 0)
{
--m_size;
T item = m_array[m_top];
--m_top;
return item;
}
throw StackEmptyException();
}
T peek() const
{
if (m_size == 0) throw StackEmptyException();
T item = m_array[m_top];
return item;
}
bool empty() const
{
return m_size == 0;
}
size_t size() const
{
return m_size;
}
private:
T* m_array;
size_t m_size;
int m_top;
};
导致堆损坏的单元测试。
TEST_METHOD(CustomStackPopException)
{
Stack<int> stack;
Assert::ExpectException<StackEmptyException>([&] { stack.pop(); });
}
TEST_METHOD(CustomStackPeekException)
{
Stack<int> stack;
Assert::ExpectException<StackEmptyException>([&] { int a = stack.peek(); });
}
TEST_METHOD(CustomStackOverflowException)
{
Stack<int> stack;
const auto functor = [&]
{
for(auto i = 0; i <= Stack<int>::MAX_SIZE; ++i)
{
stack.push(i);
}
};
Assert::ExpectException<StackOverflowException>(functor);
}
当它到达第一个测试时,它会弹出一个警告说:
HEAP CORRUPTION DETECTED: after Normal block(#279) at 0x0000020298CBC60.
CRT detected that the application wrote to memory after end of heap buffer.
我尝试在堆上创建堆栈对象,但这会导致同样的错误。
【问题讨论】:
-
您的
Stack用户定义的赋值运算符在哪里?没有它,您的课程无法安全复制。Stack& operator=(const Stack&)-- 这就是完成“规则3”需要实现的功能。 -
正确,我打算实施五法则,但之前想解决这个问题。
-
m_size和m_top始终具有相同的值。 (其中之一是不必要的,因为您希望顶部索引比元素数少一。) -
正如@VladFromMoscow 所指出的,push 方法正在访问其分配的内存之外的内存,这会导致
CustomStackOverflowException测试中的内存损坏。在您尝试删除它之前,通常不会发现内存损坏。这可能是你的问题。 -
@Styn -- 缺少用户定义的赋值运算符也可能导致堆损坏。那些
TEST_METHOD不是标准宏,因此关于为什么会出现堆损坏的所有可能性都摆在桌面上。
标签: c++ memory-management stack heap-corruption