Что может вызвать ошибку сегментации при использовании команды удаления в C ++? - PullRequest
9 голосов
/ 22 марта 2011

Я написал программу, которая выделяет новый объект класса T следующим образом:

T* obj = new T(tid);  

где tid - это int

Где-то еще в моем коде япытается освободить объект, который я выделил, который находится внутри вектора, используя:

delete(myVec[i]);  

и затем:

myVec[i] = NULL;

Иногда это проходит без каких-либо ошибок, а в некоторых случаяхэто вызывает сбой - ошибка сегментации.

Я проверил перед вызовом удаления, и этот объект есть - я не удалил его ранее нигде.

Что может вызвать этот сбой?
Это мой код для вставки объектов типа T в вектор:

_myVec is global

int add() {     

int tid =  _myVec.size();  
T* newT = new T (tid);  
    if (newT == NULL){  
        return ERR_CODE;  
    }  
    _myVec.push_back(newT);  
//  _myVec.push_back(new T (tid));  

    return tid;  
} 

как есть - иногда происходит сбой программы.
Когда я заменяю строку push_back на строку с комментариями,а остальное оставь как есть - все работает.

, но когда я заменяю этот код на:

int add() { 

int tid =  _myVec.size();  
    if (newT == NULL){  
        return ERR_CODE;  
    }  
    _myVec.push_back(new T (tid));  

    return tid;  
}  

, он падает на другом этапе ...

newT во втором варианте не используется, и все же -меняет весь процесс ... что здесь происходит?

Ответы [ 5 ]

16 голосов
/ 22 марта 2011

Сегфагтинг означает попытку манипулировать областью памяти, которая не должна быть доступна приложению.

Это означает, что ваша проблема может возникнуть из трех случаев:

  1. Попытка сделатьчто-то с указателем, который указывает на NULL;
  2. Попытка сделать что-то с неинициализированным указателем;
  3. Попытка сделать что-то с указателем, который указывает на удаленный объект;

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

2) тоже может случиться.В вашем случае вы используете std :: vector, верно?Убедитесь, что неявные манипуляции с вектором (например, перераспределение внутреннего буфера, когда он уже недостаточно велик) не повредят ваш список.

Итак, сначала убедитесь, что вы удалили указатели NULL (обратите внимание, что delete(NULL) не сгенерирует! Это стандартное и правильное поведение!) - в вашем случае вам не нужно пытаться удалить (NULL).Тогда, если этого никогда не произойдет, убедитесь, что у вас нет векторного заполнения указателями, указывающими на корзину.Например, вам следует убедиться, что вы знакомы с идиомой [Remove-Erase] [1].


Теперь, когда вы добавили некоторый код, я думаю, что вижу проблему:

int tid =  _myVec.size(); 

В качестве идентификаторов вы используете indice.

Теперь все зависит от того, как вы удаляете свои объекты. (пожалуйста, покажите его для более полного ответа)

  1. Вы просто установите указатель на NULL.
  2. Вы удаляете указатель из вектора.

Если вы только делаете 1), тогда это должно быть безопасно (если вам не нужен вектор, который растет и никогдаполучить релиз и идентификаторы не используются повторно).Если вы сделаете 2., то это все неправильно: каждый раз, когда вы удаляете объект из вектора, весь объект все еще содержится после того, как положение удаленного объекта будет понижено на единицу.Принятие недопустимым любого сохраненного идентификатора / индекса.

Убедитесь, что вы последовательны в этом, это, безусловно, источник ошибок.

1 голос
/ 22 марта 2011

что ошибка сегментации наиболее вероятна и является нарушением доступа к памяти.Некоторые причины

1) объект уже освобожден.убедитесь, что вы установили эту позицию массива в NULL после удаления 2) у вас нет границ массива 3) если вы обращаетесь к этому массиву из нескольких потоков, убедитесь, что вы синхронизируете правильно

0 голосов
/ 22 марта 2011

Вы не можете быть уверены, что объект все еще действителен: память, которая была занята объектом, не обязательно очищается, и, следовательно, вы можете видеть то, что кажется вашим объектом, но это больше не так.

Вы можете использовать метку, чтобы убедиться, что объект все еще жив, и удалить эту метку в деструкторе.

class A {
public:
    static const unsigned int Inactive;
    static const unsigned int Active;

    A();
    ~A();

    /* more things ...*/
private:
    unsigned int mark;
};

const unsigned int A::Inactive = 0xDEADBEEF;
const unsigned int A::Active = 0x11BEBEEF;

A::A() : mark( Active )
{}

A::~A()
{
    mark = Inactive;
}

Таким образом, проверяя первые 4 байта в вашем объектеВы можете легко проверить, закончил ли ваш объект его жизнь или нет.

0 голосов
/ 22 марта 2011

Вы должны попробовать использовать ptr_vector , в отличие от вашего кода, он гарантированно безопасен для исключений.

Подсказка: если вы пишете delete, вы делаете это неправильно

0 голосов
/ 22 марта 2011

Если вы абсолютно уверены, что указатель указывает на действительный объект и что удаление его вызывает сбой, значит, у вас повреждена куча.

...