Как обнаружить или предотвратить дикий указатель - PullRequest
0 голосов
/ 07 декабря 2011

Этот очень простой код демонстрирует тип неполадок, вызываемых диким указателем в сложной среде.

int main()
{
    int *a1 = new int;
    int *tmp = a1;
    delete a1;
    // Now, the tmp pointer is a wild pointer, it's dangerous.

    int *a2 = new int;
    delete tmp;
    // Now, the a2 pointer may be a wild pointer.
}

Есть ли способ обнаружить или предотвратить проблему?Помогают ли здесь умные указатели?

Ответы [ 6 ]

2 голосов
/ 07 декабря 2011

Решение этой проблемы очень простое:

Всегда помните о владении ресурсами в коде и применяйте это владение с помощью классов, управляющих временем жизни ресурсов.

В этом случае (при условии, что вам вообще нужно использовать указатели), я бы предложил следующие времена жизни:

//Limit the scope of the variables to the minimum required:
{
    //a1 owns the pointer, so make it a `unique_ptr`
    std::unique_ptr<int> a1(new int);
    //tmp does not own the pointer, so make it a raw pointer
    //limit its scope to a shorter scope than a1
    int *tmp = a1.get();
}
//now the tmp pointer does not exist. It cannot be dangerous

//A similar strategy applies here
{
    //a2 owns the pointer
    std::unique_ptr<int> a2(new int);
}
//Again, a2 goes out of scope before any damage can occur.
2 голосов
/ 07 декабря 2011

Вы можете использовать (по крайней мере в Linux) инструменты, такие как valgrind , чтобы преследовать такие ошибки.

И вы также можете использовать Сборщик мусора Бома (и не беспокоиться об освобождении памяти).

Некоторые (имхо плохо спроектированные) классы требуют удаления (т. Е. Потому что они делают важные вещи в деструкторах, помимо освобождения памяти) или не должны иметь ручных указателей на экземпляры.

Подробнее о RAII (который очень распространен в C ++, но не является универсальной мантрой: например, хороший код Ocaml не следует ему).

И вы можете использовать умные указатели.

2 голосов
/ 07 декабря 2011

Используйте умные указатели.Почему бы и нет?

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

0 голосов
/ 07 декабря 2011

С C никто не мешает вам выстрелить себе в ногу.

Существуют способы облегчить себе жизнь, такие как интеллектуальные указатели C ++: http://en.wikipedia.org/wiki/Smart_pointer#C.2B.2B_Smart_Pointers

Такие инструменты, как valgrind, будут переопределять оператор delete и помечать память как недействительную, чтобы последующий доступ можно было обнаружить и сообщить о нем. Например, популярно перезаписывать такую ​​предполагаемую удаляемую память такими значениями, как 0xDEADBEEF, которые выделяются при отладке, поэтому вы быстро знаете, что обращаетесь к удаленной области памяти.

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

0 голосов
/ 07 декабря 2011
int *a2 = new int;
delete tmp;
//now, the a2 pointer may be a wild pointer

Нет, указатель a2 указывает на действительное (не free'd) местоположение.

Насколько я знаю, не существует такого способа узнать, указывает ли указатель надопустимое (не free'd) место в памяти как таковое.

В качестве первого примера вы могли бы использовать std::shared_ptr для моделирования этого общего владения по выделенной ячейке памяти.

0 голосов
/ 07 декабря 2011

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

...