我最近在用vector作为成员编码类时遇到了一个奇怪的错误。该错误由我自己介绍,但是运行时结果令我震惊。简化示例如下所示。
基本上,该错误存在于构造函数中,该构造函数h2
的大小仅为,dimension_
而不是dimension_*dimension_
,这导致对h2
invoid A::set()
和的超出范围的访问double A::get()
。我承认有这种错误对我来说是不好的。我会认为它应该出现的情况是h[2]
,并h[3]
在void A::set()
将访问一些随机的内存地址,或只是在载体的保留范围h2
。但是真正发生的是,当析构函数被称为free()
错误时,会引发一个错误,然后是很多虚拟的Backtrace,我不想在这里列出。
*** glibc detected *** ./a.out: free(): invalid next size (fast): 0x0000000001637040 ***
但是,如果我不访问h[3]
中void A::set()
,不会出现这种情况。我的问题是向量和析构函数到底发生了什么?向量的析构函数是否知道我访问了哪些元素?我认为向量仅在调用析构函数时才知道其大小并释放内存。任何想法将不胜感激。谢谢。
以下是显示运行时错误的示例代码。
#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;
}
operator[]
用超出范围的参数调用向量的会导致未定义的行为(UB),因此从技术上讲,任何事情都可能发生,包括您所发生的情况。一旦您调用UB,所有的赌注都将关闭。您无法提前推断出调用UB的代码的效果。
请注意,at()
如果您尝试访问越界元素,则该方法将进行边界检查,并会引发异常。如果您确实访问了一个超出范围的元素,那么此时您将获得一个异常,这使得调试更加容易。缺点是边界检查会花费一些额外的时间,因此,如果您要进行数百万个向量访问,则可能会发现at()
它比慢一些operator[]
。权衡是否值得取决于您。
话虽如此,可能正在发生的事情是您破坏了C ++实现的堆分配器使用的某些簿记结构。堆分配器通常会分配比请求更多的内存,并使用额外的空间来存储有关分配本身的数据。
当向量释放用于保留向量中元素的分配时,分配器会发现其簿记数据已被破坏,因此您将获得此断言。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句