Недавно я столкнулся с странной ошибкой при кодировании классов с вектором в качестве члена. Ошибка была введена мной, но результат выполнения меня шокировал. Ниже приведен упрощенный пример.уничтожение объекта с векторным членом
В основном ошибка в конструкторе, где h2
имеет только размер dimension_
, а не dimension_*dimension_
, что приводит к вне диапазона доступа h2
в void A::set()
и double A::get()
. Я признаю, что мне плохо, что такая ошибка. Я бы подумал, что это должно произойти, так это то, что h[2]
и h[3]
в void A::set()
будут иметь доступ к некоторому случайному адресу памяти или только в зарезервированном диапазоне векторов h2
. Но то, что на самом деле произошло, когда деструктор называется ошибкой free()
, возникает ошибка, которая сопровождается множеством фиктивных обратных линий, которые я бы предпочел не перечислять здесь.
*** 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;
}
Я не думал, что UB может быть настолько глубоким. Я должен сказать, что эта ошибка действительно дала мне некоторое время в отладке. Спасибо, что указали метод 'at()'. Я знал этот метод, но я также знаю, что для проверки границ есть оценка производительности, поэтому для вектора, размер которого известен мне, я предпочитаю 'operator []'. – Devin
Спасибо за ваш ответ, который имеет для меня полный смысл. Я думаю, что я должен использовать 'at()' при отладке. – Devin
Обратите внимание, что большинство реализаций 'std :: vector' будут проверять границы, если вы скомпилируете его правильно: по умолчанию используется MSC, с g ++, за исключением оптимизированных построений, вы должны использовать' -D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC'.Когда у вас есть ошибка границ, вы не делаете _not_ хотите выбросить исключение. –