我最近在编码以 vector 为成员的类时遇到了一个奇怪的错误。这个bug是我自己引入的,但是运行结果让我震惊。简化的示例如下所示。
基本上,该错误存在于构造函数中,其中 h2
的大小仅为 dimension_
而不是 dimension_*dimension_
,这会导致 out- void A::set()
和 double A::get()
中的 h2
的范围外访问。我承认有这样的bug是我的错。我认为应该发生的是 void A::set()
中的 h[2]
和 h[3]
将访问一些随机内存地址或 vector h2
的保留范围内。但真正发生的事情是,当调用析构函数时,会引发 free()
错误,随后会出现大量虚拟回溯,我不想在这里列出。
*** glibc detected *** ./a.out: free(): invalid next size (fast): 0x0000000001637040 ***
但是如果我不在 void A::set()
中访问 h[3]
,这种情况就不会发生。我的问题是 vector 和析构函数到底发生了什么? vector 的析构函数知道我访问了哪些元素吗?我认为 vector 只知道它的大小并在调用析构函数时释放内存。
任何想法将不胜感激。谢谢。
以下是显示运行时错误的示例代码。
#include<vector>
#include<cstddef>
#include<iostream>
class A
{
public:
A(size_t dimension);
virtual ~A();
public:
virtual double get();
virtual void set();
protected:
const size_t dimension_;
std::vector<double> h1, h2;
};
A::A(size_t dimension):
dimension_(dimension),
h1(dimension_*dimension_),
h2(dimension)
{}
A::~A()
{
}
double A::get()
{
set();
double result(0), temp(0);
for(size_t i(0); i < dimension_; ++i)
{
temp = 0;
for(size_t j(0); j < dimension_; ++j)
{
temp += h1[j] * h2[j + i*dimension_];
}
result += temp * h1[i];
}
return result;
}
void A::set()
{
h1[0] = h1[1] = h1[2] = h1[3] = 0.5;
h2[0] = h2[1] = h2[2] = h2[3] = 0.005;
}
int main()
{
A mya(2);
std::cout << mya.get() << "\n";
return 0;
}
最佳答案
调用 vector 的operator[]
超出范围的参数会导致未定义的行为 (UB),因此从技术上讲任何事情都可能发生,包括您的案例中发生的情况。一旦你调用 UB,一切就都结束了;您无法提前推断调用 UB 的代码的效果。
请注意 at()
方法将进行边界检查,如果您尝试访问越界元素,则会抛出异常。如果您确实访问了越界元素,您将立即收到异常,这使得调试更加容易。缺点是边界检查需要一些额外的时间,因此如果您正在进行数百万次 vector 访问,您可能会注意到 at()
比 operator[]< 慢一点
。这种权衡是否值得取决于您。
话虽如此,可能发生的情况是您正在破坏 C++ 实现的堆分配器使用的一些簿记结构。堆分配器通常分配比请求多一点的内存,并使用额外的空间来存储有关分配本身的数据。
当 vector 释放用于保存 vector 中元素的分配时,分配器发现其簿记数据已被破坏,因此您最终会得到此断言。
关于c++ - 使用 vector 成员破坏对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26491416/