Nowoczesne najlepsze rozwiązania w języku C++ dotyczące wyjątków i obsługi błędówModern C++ best practices for exceptions and error handling

W nowoczesnych językach C++ w większości scenariuszy preferowany sposób raportowania i obsługi błędów logiki i błędów środowiska uruchomieniowego polega na użyciu wyjątków.In modern C++, in most scenarios, the preferred way to report and handle both logic errors and runtime errors is to use exceptions. Jest to szczególnie prawdziwe, gdy stos może zawierać kilka wywołań funkcji między funkcją, która wykryje błąd, a funkcją, która ma kontekst do obsługi błędu.It's especially true when the stack might contain several function calls between the function that detects the error, and the function that has the context to handle the error. Wyjątki zapewniają formalny, dobrze zdefiniowany sposób dla kodu, który wykrywa błędy w celu przekazania informacji do stosu wywołań.Exceptions provide a formal, well-defined way for code that detects errors to pass the information up the call stack.

Używanie wyjątków dla wyjątkowego koduUse exceptions for exceptional code

Błędy programu są często podzielone na dwie kategorie: Błędy logiczne, które są spowodowane przez błędy programistyczne, na przykład błąd "indeks poza zakresem".Program errors are often divided into two categories: Logic errors that are caused by programming mistakes, for example, an "index out of range" error. I błędy środowiska uruchomieniowego, które wykraczają poza kontrolę programisty, na przykład błąd "Usługa sieciowa niedostępna".And, runtime errors that are beyond the control of programmer, for example, a "network service unavailable" error. W programowaniu w stylu języka C i w modelu COM raportowanie błędów jest zarządzane przez zwrócenie wartości, która reprezentuje kod błędu lub kod stanu dla określonej funkcji, lub przez ustawienie zmiennej globalnej, którą obiekt wywołujący może opcjonalnie pobrać po każdym wywołaniu funkcji, aby sprawdzić, czy błędy zostały zgłoszone.In C-style programming and in COM, error reporting is managed either by returning a value that represents an error code or a status code for a particular function, or by setting a global variable that the caller may optionally retrieve after every function call to see whether errors were reported. Na przykład programowanie COM używa wartości zwracanej HRESULT do przekazywania błędów do obiektu wywołującego.For example, COM programming uses the HRESULT return value to communicate errors to the caller. Win32 API zawiera funkcję, która GetLastError umożliwia pobranie ostatniego błędu zgłoszonego przez stos wywołań.And the Win32 API has the GetLastError function to retrieve the last error that was reported by the call stack. W obu tych przypadkach jest to obiekt wywołujący, aby rozpoznać kod i odpowiednio odpowiedzieć.In both of these cases, it's up to the caller to recognize the code and respond to it appropriately. Jeśli obiekt wywołujący nie obsługuje jawnie kodu błędu, program może ulec awarii bez ostrzeżenia.If the caller doesn't explicitly handle the error code, the program might crash without warning. Może być również nadal wykonywany przy użyciu nieprawidłowych danych i generować nieprawidłowe wyniki.Or, it might continue to execute using bad data and produce incorrect results.

Wyjątki są preferowane w nowoczesnej C++ z następujących powodów:Exceptions are preferred in modern C++ for the following reasons:

  • Wyjątek wymusza Wywoływanie kodu, aby rozpoznać warunek błędu i obsłużyć go.An exception forces calling code to recognize an error condition and handle it. Nieobsłużone wyjątki zatrzymują wykonywanie programu.Unhandled exceptions stop program execution.

  • Wyjątek przeskakuje do punktu w stosie wywołań, który może obsłużyć błąd.An exception jumps to the point in the call stack that can handle the error. Funkcje pośrednie mogą pozwolić na propagację wyjątku.Intermediate functions can let the exception propagate. Nie muszą one koordynować z innymi warstwami.They don't have to coordinate with other layers.

  • Mechanizm odwracania stosu wyjątku powoduje zniszczenie wszystkich obiektów w zakresie po zgłoszeniu wyjątku zgodnie z dobrze zdefiniowanymi regułami.The exception stack-unwinding mechanism destroys all objects in scope after an exception is thrown, according to well-defined rules.

  • Wyjątek umożliwia czyste rozdzielenie kodu, który wykrywa błąd i kod, który obsłuży błąd.An exception enables a clean separation between the code that detects the error and the code that handles the error.

Poniższy uproszczony przykład pokazuje składnię niezbędną do zgłaszania i przechwytywania wyjątków w języku C++.The following simplified example shows the necessary syntax for throwing and catching exceptions in C++.

#include <stdexcept>
#include <limits>
#include <iostream>

using namespace std;

void MyFunc(int c)
{
    if (c > numeric_limits< char> ::max())
        throw invalid_argument("MyFunc argument too large.");
    //...
}

int main()
{
    try
    {
        MyFunc(256); //cause an exception to throw
    }

    catch (invalid_argument& e)
    {
        cerr << e.what() << endl;
        return -1;
    }
    //...
    return 0;
}

Wyjątki w języku C++ są podobne do tych w językach, takich jak C# i Java.Exceptions in C++ resemble ones in languages such as C# and Java. W try bloku, jeśli zostanie zgłoszony wyjątek, zostanie przechwycony przez pierwszy skojarzony catch blok, którego typ pasuje do tego wyjątku.In the try block, if an exception is thrown it will be caught by the first associated catch block whose type matches that of the exception. Innymi słowy, wykonanie przechodzi z throw instrukcji do catch instrukcji.In other words, execution jumps from the throw statement to the catch statement. Jeśli blok catch nie zostanie znaleziony, std::terminate zostanie wywołany, a program zakończy działanie.If no usable catch block is found, std::terminate is invoked and the program exits. W języku C++ można zgłaszać dowolny typ; zaleca się jednak, aby zgłosić typ, który poprowadzi bezpośrednio lub pośrednio z std::exception .In C++, any type may be thrown; however, we recommend that you throw a type that derives directly or indirectly from std::exception. W poprzednim przykładzie typ wyjątku, invalid_argument ,,, jest zdefiniowany w bibliotece standardowej w <stdexcept> pliku nagłówkowym.In the previous example, the exception type, invalid_argument, is defined in the standard library in the <stdexcept> header file. Język C++ nie udostępnia lub nie wymaga finally bloku, aby upewnić się, że wszystkie zasoby są wydane, jeśli wystąpi wyjątek.C++ doesn't provide or require a finally block to make sure all resources are released if an exception is thrown. Funkcja pozyskiwania zasobów jest inicjowana (RAII) idiom, która używa inteligentnych wskaźników, zapewnia funkcje wymagane do oczyszczenia zasobów.The resource acquisition is initialization (RAII) idiom, which uses smart pointers, provides the required functionality for resource cleanup. Aby uzyskać więcej informacji, zobacz jak: projektowanie pod kątem bezpieczeństwa wyjątków.For more information, see How to: Design for exception safety. Aby uzyskać informacje o mechanizmie odwracania stosu języka C++, zobacz wyjątki i rozwinięcia stosu.For information about the C++ stack-unwinding mechanism, see Exceptions and stack unwinding.

Podstawowe wytyczneBasic guidelines

Niezawodna obsługa błędów jest trudne w każdym języku programowania.Robust error handling is challenging in any programming language. Chociaż wyjątki udostępniają kilka funkcji, które obsługują dobrą obsługę błędów, nie mogą wykonać całej pracy za Ciebie.Although exceptions provide several features that support good error handling, they can't do all the work for you. Aby zrealizować zalety mechanizmu wyjątków, należy zachować wyjątki podczas projektowania kodu.To realize the benefits of the exception mechanism, keep exceptions in mind as you design your code.

  • Użyj potwierdzeń, aby wyszukać błędy, które nigdy nie powinny wystąpić.Use asserts to check for errors that should never occur. Użyj wyjątków, aby wyszukać błędy, które mogą wystąpić, na przykład błędy sprawdzania poprawności danych wejściowych w parametrach funkcji publicznych.Use exceptions to check for errors that might occur, for example, errors in input validation on parameters of public functions. Aby uzyskać więcej informacji, zobacz sekcję wyjątki w porównaniu z potwierdzeniami .For more information, see the Exceptions versus assertions section.

  • Wyjątki należy stosować, gdy kod, który obsługuje błąd jest oddzielony od kodu, który wykrywa błąd przez jedno lub więcej wywoływanych funkcji.Use exceptions when the code that handles the error is separated from the code that detects the error by one or more intervening function calls. Należy rozważyć, czy należy używać kodów błędów zamiast w przypadku pętli krytycznych dla wydajności, gdy kod, który obsługuje błąd jest ściśle połączony z kodem, który go wykryje.Consider whether to use error codes instead in performance-critical loops, when code that handles the error is tightly coupled to the code that detects it.

  • Dla każdej funkcji, która może zgłosić lub propagować wyjątek, należy podać jedno z trzech gwarancji wyjątku: silna gwarancja, gwarancja podstawowa lub gwarancja nothrow (noexcept).For every function that might throw or propagate an exception, provide one of the three exception guarantees: the strong guarantee, the basic guarantee, or the nothrow (noexcept) guarantee. Aby uzyskać więcej informacji, zobacz jak: projektowanie pod kątem bezpieczeństwa wyjątków.For more information, see How to: Design for exception safety.

  • Zgłoś wyjątki według wartości, należy je przechwycić przez odwołanie.Throw exceptions by value, catch them by reference. Nie Przechwytuj tego, czego nie można obsłużyć.Don’t catch what you can't handle.

  • Nie używaj specyfikacji wyjątków, które są przestarzałe w języku C++ 11.Don't use exception specifications, which are deprecated in C++11. Aby uzyskać więcej informacji, zobacz sekcję specyfikacje i noexcept wymagania dotyczące wyjątków .For more information, see the Exception specifications and noexcept section.

  • Użyj standardowych typów wyjątków biblioteki, gdy mają zastosowanie.Use standard library exception types when they apply. Utwórz niestandardowe typy wyjątków z hierarchii exception klas .Derive custom exception types from the exception Class hierarchy.

  • Nie Zezwalaj na wyjątki do ucieczki z destruktorów lub funkcji dealokacji pamięci.Don't allow exceptions to escape from destructors or memory-deallocation functions.

Wyjątki i wydajnośćExceptions and performance

Mechanizm wyjątków ma minimalny koszt wydajności, jeśli nie zostanie zgłoszony żaden wyjątek.The exception mechanism has a minimal performance cost if no exception is thrown. Jeśli wystąpi wyjątek, koszt przechodzenia stosu i rozwinięcia jest w przybliżeniu porównywalny do kosztu wywołania funkcji.If an exception is thrown, the cost of the stack traversal and unwinding is roughly comparable to the cost of a function call. Dodatkowe struktury danych są wymagane do śledzenia stosu wywołań po try wprowadzeniu bloku, a dodatkowe instrukcje są wymagane do odwinięcia stosu, jeśli wystąpi wyjątek.Additional data structures are required to track the call stack after a try block is entered, and additional instructions are required to unwind the stack if an exception is thrown. Jednak w większości scenariuszy koszt wydajności i pamięci nie jest znaczący.However, in most scenarios, the cost in performance and memory footprint isn't significant. Niekorzystny wpływ wyjątków na wydajność jest prawdopodobnie znaczący tylko w systemach z ograniczoną ilością pamięci.The adverse effect of exceptions on performance is likely to be significant only on memory-constrained systems. Lub w przypadku pętli krytycznych dla wydajności, w przypadku których błąd może wystąpić regularnie i istnieje ścisłe sprzężenie między kodem, który go obsługuje, i kod, który go zgłasza.Or, in performance-critical loops, where an error is likely to occur regularly and there's tight coupling between the code to handle it and the code that reports it. W każdym przypadku nie można znać rzeczywistego kosztu wyjątków bez profilowania i pomiaru.In any case, it's impossible to know the actual cost of exceptions without profiling and measuring. Nawet w rzadkich przypadkach, gdy koszt jest znaczący, można go zważyć z większą dokładnością, łatwiejszym konserwacją i innymi korzyściami, które są udostępniane przez dobrze zaprojektowane zasady wyjątków.Even in those rare cases when the cost is significant, you can weigh it against the increased correctness, easier maintainability, and other advantages that are provided by a well-designed exception policy.

Wyjątki a potwierdzeniaExceptions versus assertions

Wyjątki i potwierdzenia to dwa odrębne mechanizmy wykrywania błędów czasu wykonywania w programie.Exceptions and asserts are two distinct mechanisms for detecting run-time errors in a program. Używaj assert instrukcji do testowania pod kątem warunków podczas opracowywania, które nigdy nie powinny być prawdziwe, jeśli cały kod jest poprawny.Use assert statements to test for conditions during development that should never be true if all your code is correct. Nie ma żadnego punktu na obsłudze takiego błędu przy użyciu wyjątku, ponieważ błąd wskazuje, że coś w kodzie musi być ustalone.There's no point in handling such an error by using an exception, because the error indicates that something in the code has to be fixed. Nie reprezentuje warunku, z którego program ma wykonać odzyskiwanie w czasie wykonywania.It doesn't represent a condition that the program has to recover from at run time. Powoduje assert zatrzymanie wykonywania instrukcji w celu sprawdzenia stanu programu w debugerze.An assert stops execution at the statement so that you can inspect the program state in the debugger. Wyjątek kontynuuje wykonywanie od pierwszego odpowiedniej procedury obsługi catch.An exception continues execution from the first appropriate catch handler. Użyj wyjątków, aby sprawdzić warunki błędów, które mogą wystąpić w czasie wykonywania nawet wtedy, gdy kod jest poprawny, na przykład "nie znaleziono pliku" lub "Brak pamięci".Use exceptions to check error conditions that might occur at run time even if your code is correct, for example, "file not found" or "out of memory." Wyjątki mogą obsługiwać te warunki, nawet jeśli odzyskiwanie tylko wysyła komunikat do dziennika i zatrzymuje program.Exceptions can handle these conditions, even if the recovery just outputs a message to a log and ends the program. Zawsze sprawdzaj argumenty funkcji publicznych przy użyciu wyjątków.Always check arguments to public functions by using exceptions. Nawet jeśli funkcja jest bezpłatna bez błędów, może nie mieć pełnej kontroli nad argumentami, które użytkownik może przekazać do niego.Even if your function is error-free, you might not have complete control over arguments that a user might pass to it.

Wyjątki C++ a wyjątki SEH systemu WindowsC++ exceptions versus Windows SEH exceptions

Programy C i C++ mogą korzystać z mechanizmu obsługi wyjątków strukturalnych (SEH) w systemie operacyjnym Windows.Both C and C++ programs can use the structured exception handling (SEH) mechanism in the Windows operating system. Koncepcje w SEH przypominają te w wyjątkach C++, z tą różnicą, że SEH korzysta z __try __except konstrukcji,, i __finally zamiast try i catch .The concepts in SEH resemble the ones in C++ exceptions, except that SEH uses the __try, __except, and __finally constructs instead of try and catch. W kompilatorze języka Microsoft C++ (MSVC) wyjątki języka C++ są implementowane dla SEH.In the Microsoft C++ compiler (MSVC), C++ exceptions are implemented for SEH. Jednak podczas pisania kodu C++ należy użyć składni wyjątków C++.However, when you write C++ code, use the C++ exception syntax.

Aby uzyskać więcej informacji na temat SEH, zobacz Obsługa wyjątków strukturalnych (C/C++).For more information about SEH, see Structured Exception Handling (C/C++).

Specyfikacje wyjątków i noexceptException specifications and noexcept

Specyfikacje wyjątków zostały wprowadzone w języku C++ jako sposób, aby określić wyjątki, które może zgłosić funkcja.Exception specifications were introduced in C++ as a way to specify the exceptions that a function might throw. Jednakże specyfikacje wyjątków okazały się problematyczne i są przestarzałe w standardowym projekcie C++ 11.However, exception specifications proved problematic in practice, and are deprecated in the C++11 draft standard. Zaleca się, aby nie używać throw specyfikacji wyjątków, z wyjątkiem throw() , co oznacza, że funkcja nie zezwala na ucieczki wyjątków.We recommend that you don't use throw exception specifications except for throw(), which indicates that the function allows no exceptions to escape. Jeśli musisz użyć specyfikacji wyjątków w postaci przestarzałej throw( type-name ) , pomoc techniczna MSVC jest ograniczona.If you must use exception specifications of the deprecated form throw( type-name ), MSVC support is limited. Aby uzyskać więcej informacji, zobacz specyfikacje wyjątków (throw).For more information, see Exception Specifications (throw). noexcept Specyfikator jest wprowadzany w języku c++ 11 jako preferowana alternatywa dla throw() .The noexcept specifier is introduced in C++11 as the preferred alternative to throw().

Zobacz teżSee also

Instrukcje: interfejs między wyjątkowym i niewyjątkowym kodemHow to: Interface between exceptional and non-exceptional code
Dokumentacja języka C++C++ language reference
Standardowa biblioteka języka C++C++ Standard Library