Преодоление неправильного выделения памяти в C ++ - PullRequest
0 голосов
/ 11 июня 2009

В программе на C ++ я пишу:

#include<iostream>
#include<vector>
using namespace std;
int main()
{
   vector<int> a;
   a.resize(1); 
   for( int i = 0 ; i < 10 ; i++ ) {
       cout << a[i] << " ";
   }

   return 0;
}

эта программа печатает правильное значение [0] (потому что оно выделено), но также печатает значения в остальных 10 местах, вместо того, чтобы давать ошибку сегментации.

Как преодолеть это при написании кода? Это вызывает проблемы, когда ваш код что-то вычисляет и успешно обращается к памяти, не предназначенной для доступа.

Ответы [ 9 ]

13 голосов
/ 11 июня 2009

Используйте это:

a.at(i)

at() сгенерирует исключение out_of_range, если индекс выходит за пределы.

Причина, по которой operator [] не выполняет проверку границ, заключается в эффективности. Возможно, вы захотите использовать at() для индексации по вектору, если у вас нет веских причин не делать это в конкретном случае.

10 голосов
/ 11 июня 2009

Когда вы вызываете resize (), реализация вектора перераспределяет буфер до размера , достаточного для хранения запрошенного количества элементов - оно не может быть меньше, чем требуется, но реализация может сделать это больше, чтобы уменьшить фрагментацию памяти и делать перераспределение реже.

Единственный способ избежать таких ошибок - это зацикливаться только в пределах допустимого диапазона индексов в вашем коде. Для кода, который вы указали, подойдет следующее:

for ( int i = 0 ; i < a.size(); i++ ) {
    cout << a[i] << " ";
}
5 голосов
/ 11 июня 2009

Вы можете полностью избежать этой проблемы, используя итераторы. Цикл for будет выглядеть примерно так:

for(vector<int>::iterator i = a.begin(); i != a.end(); ++i)
    cout << *i << " ";
2 голосов
/ 11 июня 2009

Это не вопрос распределения памяти как таковой, это вопрос проверки границ. Если память, которую вы переполнили (либо для чтения, либо для записи), по-прежнему находится в допустимых пределах программы, вы не будете иметь ошибки по умолчанию.

В прошлом я видел перегруженный оператор [, который выполняет проверку границ. Было много работы, чтобы превратить C ++ в ForTran (я мог бы добавить, что это одна из лучших функций ForTran).

Помимо использования векторов и итераторов, лучший ответ - использовать хорошую технику программирования.

0 голосов
/ 17 июня 2009

Доступ к элементам за пределами выделенного объекта приводит к неопределенному поведению . Это означает, что реализация бесплатна для всего, что с ней происходит. Это может бросить и исключение, если вам очень повезет. Если вам очень не повезло, это просто сработает.

В принципе, разрешено, чтобы демоны вылетали из вашего носа.

Его поведение: undefined .

0 голосов
/ 11 июня 2009

Ошибка сегментации происходит из-за того, что аппаратное обеспечение (модуль управления памятью) определяет, что у вас нет доступа к региону, и выдает исключение. ОС получает это исключение и решает, что с ним делать; в этих случаях он понимает, что вы делаете незаконный доступ, и убивает ваше приложение из-за ошибки сегментации.

Тот же механизм, как реализован своп; ОС может восстановить, что у вас do есть доступ к памяти, но она сейчас на диске. Затем он загружает память с диска и позволяет продолжить выполнение вашей программы.

Однако вся эта схема защиты памяти имеет достаточное разрешение только для страниц памяти, например 4 Кб одновременно. Таким образом, MMU не может защитить вас от каждого небольшого перебора, который вы можете сделать. Существуют такие инструменты, как ElectricFences, которые заменяют malloc и free и используют преимущества MMU, но они предназначены только для «выборочных проверок» ... они хороши для отладки, но вы не захотите работать так всегда. 1007 *

0 голосов
/ 11 июня 2009

Я пока не могу комментировать, но resize () не является подсказкой для выделения памяти. Согласно документации STL , resize (n) вставляет или удаляет элементы в конце вектора. Поэтому после вызова resize (1) вектор содержит ровно 1 элемент. Чтобы заранее выделить память, вы должны вызвать функцию резерва (n).

0 голосов
/ 11 июня 2009

Преодолейте эту проблему, проявив больше совести при обращении к памяти: проверьте границы!

0 голосов
/ 11 июня 2009

Проверьте размер, который вы выделяете для вектора

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...