Я рекомендовал бы Вам использовать valgrind
для Linux. Это поймает не освобожденную память среди других ошибок как запись в освобожденную память. Другая опция является брызговиком, который говорит Вам о не освобожденная память также. Используйте -fmudflap -lmudflap
опции с gcc, затем запустите свою программу с MUDFLAP_OPTIONS=-print-leaks ./my_program
.
Вот некоторый очень простой код. Это не подходит для сложного отслеживания, но предназначенное, чтобы показать Вам, как Вы сделали бы это в принципе, если бы необходимо было реализовать его сами. Что-то вроде этого (не учел материал, назвав зарегистрированный new_handler и другие детали).
template<typename T>
struct track_alloc : std::allocator<T> {
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
template<typename U>
struct rebind {
typedef track_alloc<U> other;
};
track_alloc() {}
template<typename U>
track_alloc(track_alloc<U> const& u)
:std::allocator<T>(u) {}
pointer allocate(size_type size,
std::allocator<void>::const_pointer = 0) {
void * p = std::malloc(size * sizeof(T));
if(p == 0) {
throw std::bad_alloc();
}
return static_cast<pointer>(p);
}
void deallocate(pointer p, size_type) {
std::free(p);
}
};
typedef std::map< void*, std::size_t, std::less<void*>,
track_alloc< std::pair<void* const, std::size_t> > > track_type;
struct track_printer {
track_type * track;
track_printer(track_type * track):track(track) {}
~track_printer() {
track_type::const_iterator it = track->begin();
while(it != track->end()) {
std::cerr << "TRACK: leaked at " << it->first << ", "
<< it->second << " bytes\n";
++it;
}
}
};
track_type * get_map() {
// don't use normal new to avoid infinite recursion.
static track_type * track = new (std::malloc(sizeof *track))
track_type;
static track_printer printer(track);
return track;
}
void * operator new(std::size_t size) throw(std::bad_alloc) {
// we are required to return non-null
void * mem = std::malloc(size == 0 ? 1 : size);
if(mem == 0) {
throw std::bad_alloc();
}
(*get_map())[mem] = size;
return mem;
}
void operator delete(void * mem) throw() {
if(get_map()->erase(mem) == 0) {
// this indicates a serious bug
std::cerr << "bug: memory at "
<< mem << " wasn't allocated by us\n";
}
std::free(mem);
}
int main() {
std::string *s = new std::string;
// will print something like: TRACK: leaked at 0x9564008, 4 bytes
}
Мы должны использовать наше собственное средство выделения для нашей карты, потому что стандартный будет использовать наш переопределенный новый оператор, который привел бы к бесконечной рекурсии.
Удостоверяются, переопределяете ли Вы новый оператор, Вы используете карту для регистрации выделений. Удаление памяти, выделенной формами размещения новых, будет использовать тот оператор delete также, таким образом, это сможет стать хитрым, если некоторый код, который Вы не знаете, перегрузил оператор, новый не использование Вашей карты, потому что оператор удаляет, скажет Вам, что это не было выделено, и используйте std::free
для освобождения памяти.
Также примечание, как Мир указанный для его решения также, это только покажет утечки, которые вызываются кодом с помощью нашего собственного определенного оператора, new/delete. Таким образом, если Вы хотите использовать их, поместить их объявление в заголовок и включать его во все файлы, за которыми нужно наблюдать.
Вы можете создать метод SkipOnError следующим образом:
private SkipOnError(Action action)
{
try
{
action();
}
catch
{
}
}
Затем вы можете вызвать его так:
try
{
SkipOnError(() => /*line1*/);
line2;
line3;
} catch {}
Изменить: Это должно упростить пропуск данного исключения:
private SkipOnError(Action action, Type exceptionToSkip)
{
try
{
action();
}
catch (Exception e)
{
if (e.GetType() != exceptionToSkip) throw;
}
}
ПРИМЕЧАНИЕ: Я на самом деле не предлагаю вам делать это - по крайней мере, не на регулярной основе, поскольку я сам считаю это довольно хакерским. Но он как бы демонстрирует некоторые функциональные возможности, которые мы теперь можем делать на C #, ура!
На самом деле я бы сделал следующее: Рефакторинг line1
в метод ( Extract Method ). Этот новый метод должен обрабатывать любые предсказуемые исключения (если они могут быть обработаны) и, таким образом, оставлять вызывающего в известном состоянии. Потому что иногда вы действительно хотите сделать line1
, за исключением того, что, может быть, это нормально, если произойдет ошибка ...
Если возможно обработать исключение и продолжить, вам следует локализовать блоки try / catch.
try
{
line1;
}
catch (ExpectedException e)
{
// Handle your exception, prepare data for the next lines
// Could you have prevented the exception in the first place?
}
try
{
line2;
line3;
}
catch (AnotherExpectedException e)
{
// Maybe this exception you can't continue from. Perhaps log it and throw;
}
Помните, что исключения являются исключительными. Если возникает исключение, что-то должно было пойти не так. В первую очередь вам следует попытаться предотвратить исключения.
Для этого вам потребуются реифицируемые продолжения. CLR и C # не поддерживают этого и, вероятно, никогда не будут этого делать. : (
try
{
line1
line2
...
}
catch (Exception ex)
{
...
}
finally
{
if(line1ErrorOccured)
{
line2
...
}
}
не указано слишком много раздумий
Как говорили другие, сначала убедитесь, что "игнорирование" исключение - это то, чем вы действительно хотите заниматься. Если это все еще так, и синтаксические накладные расходы всех try-catch слишком высоки, вы можете завершить это idom выполнения.
У меня нет времени набросать весь код прямо сейчас - но вам нужно написать метод, который принимает анонимный делегат и выполняет его в рамках try-catch (возможно, регистрируя любые исключения или фильтруя те, которые "в порядке"). Назовите этот метод чем-то вроде tryDo. Затем вы можете написать код примерно так:
tryDo( delegate(){ line1; } );
tryDo( delegate(){ line2; } );
Это все еще немного многословно, но вы не хотите делать это слишком простым. Этого достаточно, чтобы заставить вас задуматься, правильно ли это делать: -)
Как было предложено, в этом конкретном примере вам следует обернуть try catch вокруг строки1. Однако на будущее у вас должны быть только условия в вашем блоке try catch, которые вы хотите выполнить, только если нет исключений.
Вы можете поместить другие строки в предложение finally, но это было бы довольно некрасиво, особенно если они также могут вызывать исключения ...
Вы должны восстановить из первого исключения, а затем переходите к следующей строке, заключая каждую в оператор try / catch.
вы можете заключить только строку 1 в блок try catch.
Вы можете изолировать каждую строку в блоке try-catch, но мне кажется, что это просто вредные шумы. Если вы уверены , что строки после первой строки не вызывают исключений или должны выполняться независимо от исключения и не будут вызывать дополнительных ошибок, вы можете добавить блок finally после первого перехвата. Пример:
try{
line 1;
}
catch(Exception exc){
//Error handling logic here
}
finally{
line 2;
line 3;
.
.
.
line n;
}
Если есть код, который вы всегда хотите выполнять, даже если возникает исключение, даже если исключение либо не попадает в блок catch, либо блок catch повторно генерирует или генерирует новое исключение, оно должно быть в блоке "finally":
try
{
do(something);
}
catch (InvalidArgumentException ex)
{
onlyDealWithOneExceptionType();
}
finally
{
always.runs(no, matter, what);
}
просто попробуйте уловить строку1
try
{
try
{
line1
}
catch (Exception ex)
{
...
}
line2
...
}
catch (Exception ex)
{
...
}
Фредерик прав, хотя вам действительно нужно быть осторожным при этом. Его следует использовать в индивидуальном порядке. Вы можете использовать его только тогда, когда знаете, что процесс должен продолжаться. В противном случае следует обработать исключение соответствующим образом.
Исключения не следует игнорировать. :)
Они существуют и выбрасываются по какой-то причине: возникла исключительная ситуация, определенное условие не выполнено, и я не могу продолжить работу ...
Можно игнорировать исключения, если вы поместите блок try / catch вокруг каждого строчка кода, но я не думаю, что вы действительно хотите это сделать ...
Вы всегда можете сделать
try
{
line1
}
catch (Exception ex)
{
}
line2
...
Но нет ничего лучше ключевого слова 'retry'.