Misal
int *ptr;
*ptr = 1000;
Microsoft'a özgü herhangi bir kullanmadan standart C ++ kullanarak bellek erişim ihlali istisnasını yakalayabilir miyim?
Misal
int *ptr;
*ptr = 1000;
Microsoft'a özgü herhangi bir kullanmadan standart C ++ kullanarak bellek erişim ihlali istisnasını yakalayabilir miyim?
Yanıtlar:
Hayır! C ++, kötü bir şey yaptığınızda, bir performans düşüşüne neden olacak bir istisna atmaz. Erişim ihlalleri veya sıfır hatayla bölme gibi şeyler, yakalayabileceğiniz dil düzeyinde şeyler yerine daha çok "makine" istisnaları gibidir.
Oku ve ağla!
Bunu anladım. İşleyiciden atmazsanız, işleyici devam edecek ve istisna da devam edecektir.
Sihir, kendi istisnanızı attığınızda ve bununla başa çıktığınızda gerçekleşir.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <tchar.h>
void SignalHandler(int signal)
{
printf("Signal %d",signal);
throw "!Access Violation!";
}
int main()
{
typedef void (*SignalHandlerPointer)(int);
SignalHandlerPointer previousHandler;
previousHandler = signal(SIGSEGV , SignalHandler);
try{
*(int *) 0 = 0;// Baaaaaaad thing that should never be caught. You should write good code in the first place.
}
catch(char *e)
{
printf("Exception Caught: %s\n",e);
}
printf("Now we continue, unhindered, like the abomination never happened. (I am an EVIL genius)\n");
printf("But please kids, DONT TRY THIS AT HOME ;)\n");
}
sigaltstack
kurulu herhangi bir alternatif sinyal yığını ( ) bulunmamalıdır (C ++ istisna çözme uygulaması buna izin vermedikçe) ve çözme mekanizmasının kendisini işleyen her çalışma zamanı işlevi sinyal açısından güvenli olmalıdır.
signal(SIGSEGV, SIG_DFL);
Try -> catch (...) bloğu kullanarak Visual Studio'da her türlü istisnayı (sıfıra bölme, erişim ihlali vb.) Yakalamanın çok kolay bir yolu vardır . Küçük bir proje ayarlarının ince ayarlanması yeterlidir. Proje ayarlarında / EHa seçeneğini etkinleştirmeniz yeterlidir. Bkz Proje Özellikleri -> C / C ++ -> Kod Üretimi -> Değiştir "Evet SEH İstisnalar ile" C ++ İstisnalar etkinleştirin . Bu kadar!
Ayrıntılara buradan bakın: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx
En azından benim için, signal(SIGSEGV ...)
başka bir cevapta bahsedilen yaklaşım Visual C ++ 2015 ile Win32'de işe yaramadı . Ne yaptım iş için beni kullanmak oldu _set_se_translator()
bulundu eh.h
. Şu şekilde çalışır:
Adım 1 ) etkinleştirmek emin olun SEH İstisnalar (/ EHA) ile Evet de C ++ İstisnalar etkinleştirme Proje Özellikleri / C ++ / Kod Üretimi / tarafından cevapta belirtildiği gibi Volodymyr Frytskyy .
Adım 2 ) _set_se_translator()
Yeni istisna çeviricisi için bir işlev göstericisini (veya lambda) ileterek çağırın . Çevirmen olarak adlandırılır çünkü temelde sadece düşük seviyeli istisnayı alır ve onu yakalanması daha kolay bir şey olarak yeniden fırlatır, örneğin std::exception
:
#include <string>
#include <eh.h>
// Be sure to enable "Yes with SEH Exceptions (/EHa)" in C++ / Code Generation;
_set_se_translator([](unsigned int u, EXCEPTION_POINTERS *pExp) {
std::string error = "SE Exception: ";
switch (u) {
case 0xC0000005:
error += "Access Violation";
break;
default:
char result[11];
sprintf_s(result, 11, "0x%08X", u);
error += result;
};
throw std::exception(error.c_str());
});
Adım 3 ) Normalde yaptığınız gibi istisnayı yakalayın:
try{
MakeAnException();
}
catch(std::exception ex){
HandleIt();
};
Bu tür bir durum uygulamaya bağlıdır ve sonuç olarak tuzağa düşmek için satıcıya özel bir mekanizma gerektirecektir. Microsoft ile bu SEH'yi içerecek ve * nix bir sinyal içerecektir
Genel olarak, bir Erişim İhlali istisnasını yakalamak çok kötü bir fikirdir. Bir AV istisnasından kurtarmanın neredeyse hiçbir yolu yoktur ve bunu yapmaya çalışmak, programınızda hataları bulmanızı zorlaştıracaktır.
Belirtildiği gibi, bunu Windows platformunda yapmanın Microsoft / derleyici satıcısı olmayan bir yolu yoktur. Ancak, bu tür istisnaları, hata raporlama için normal try {} catch (ex istisna) {} yönteminde ve daha çok uygulamanızın zarif bir çıkışında (JaredPar'ın dediği gibi, uygulama artık büyük olasılıkla belada) yakalamakta fayda vardır. . _Se_translator_function, aa try işleyicisinde aşağıdaki istisnaları yakalamamıza izin veren basit bir sınıf sarmalayıcısında kullanırız:
DECLARE_EXCEPTION_CLASS(datatype_misalignment)
DECLARE_EXCEPTION_CLASS(breakpoint)
DECLARE_EXCEPTION_CLASS(single_step)
DECLARE_EXCEPTION_CLASS(array_bounds_exceeded)
DECLARE_EXCEPTION_CLASS(flt_denormal_operand)
DECLARE_EXCEPTION_CLASS(flt_divide_by_zero)
DECLARE_EXCEPTION_CLASS(flt_inexact_result)
DECLARE_EXCEPTION_CLASS(flt_invalid_operation)
DECLARE_EXCEPTION_CLASS(flt_overflow)
DECLARE_EXCEPTION_CLASS(flt_stack_check)
DECLARE_EXCEPTION_CLASS(flt_underflow)
DECLARE_EXCEPTION_CLASS(int_divide_by_zero)
DECLARE_EXCEPTION_CLASS(int_overflow)
DECLARE_EXCEPTION_CLASS(priv_instruction)
DECLARE_EXCEPTION_CLASS(in_page_error)
DECLARE_EXCEPTION_CLASS(illegal_instruction)
DECLARE_EXCEPTION_CLASS(noncontinuable_exception)
DECLARE_EXCEPTION_CLASS(stack_overflow)
DECLARE_EXCEPTION_CLASS(invalid_disposition)
DECLARE_EXCEPTION_CLASS(guard_page)
DECLARE_EXCEPTION_CLASS(invalid_handle)
DECLARE_EXCEPTION_CLASS(microsoft_cpp)
Orijinal sınıf bu çok faydalı makaleden geldi:
İstisna işleme mekanizması değil, ancak C tarafından sağlanan signal () mekanizmasını kullanabilirsiniz.
> man signal
11 SIGSEGV create core image segmentation violation
Bir NULL işaretçisine yazmak muhtemelen bir SIGSEGV sinyaline neden olacak
signal()
, posix standardının bir parçasıdır. Windows, posix standardını uygular (Linux ve unix gibi)
Bunun gibi bir ihlal, kodda ciddi bir yanlışlık olduğu anlamına gelir ve bu güvenilmezdir. Bir programın, kullanıcının verilerini, önceki verilerin üzerine yazmayacağını umarak, kullanıcının verilerinin zaten bozuk olmadığı umuduyla kaydetmeye çalışmak isteyebileceğini görebiliyorum, ancak tanım gereği standart bir yöntem yoktur. tanımlanmamış davranışlarla başa çıkma.