I typed this into Google, but I only found how-tos in C++.
How can I do it in C?
asked May 23, 2010 at 12:48
httpinterprethttpinterpret
6,4399 gold badges33 silver badges37 bronze badges
3
There are no exceptions in C. In C the errors are notified by the returned value of the function, the exit value of the process, signals to the process (Program Error Signals (GNU libc)) or the CPU hardware interruption (or other notification error form the CPU if there is)(How processor handles the case of division by zero).
Exceptions are defined in C++ and other languages though. Exception handling in C++ is specified in the C++ standard «S.15 Exception handling», there is no equivalent section in the C standard.
answered May 23, 2010 at 12:49
Brian R. BondyBrian R. Bondy
340k124 gold badges596 silver badges636 bronze badges
5
In C you could use the combination of the setjmp()
and longjmp()
functions, defined in setjmp.h
. Example from Wikipedia
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void second(void) {
printf("second\n"); // prints
longjmp(buf,1); // jumps back to where setjmp
// was called - making setjmp now return 1
}
void first(void) {
second();
printf("first\n"); // does not print
}
int main() {
if ( ! setjmp(buf) ) {
first(); // when executed, setjmp returns 0
} else { // when longjmp jumps back, setjmp returns 1
printf("main"); // prints
}
return 0;
}
Note: I would actually advise you not to use them as they work awful with C++ (destructors of local objects wouldn’t get called) and it is really hard to understand what is going on. Return some kind of error instead.
einpoklum
119k57 gold badges342 silver badges691 bronze badges
answered May 23, 2010 at 13:36
5
There’s no built-in exception mechanism in C; you need to simulate exceptions and their semantics. This is usually achieved by relying on setjmp
and longjmp
.
There are quite a few libraries around, and I’m implementing yet another one. It’s called exceptions4c; it’s portable and free. You may take a look at it, and compare it against other alternatives to see which fits you most.
answered Apr 28, 2011 at 18:31
3
Plain old C doesn’t actually support exceptions natively.
You can use alternative error handling strategies, such as:
- returning an error code
- returning
FALSE
and using alast_error
variable or function.
See http://en.wikibooks.org/wiki/C_Programming/Error_handling.
answered May 23, 2010 at 12:50
Lucas JonesLucas Jones
19.8k8 gold badges75 silver badges88 bronze badges
1
C is able to throw C++ exceptions. It is machine code anyway.
For example, in file bar.c:
#include <stdlib.h>
#include <stdint.h>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
int64_t * p = (int64_t*)__cxa_allocate_exception(8);
*p = 1976;
__cxa_throw(p, &_ZTIl, 0);
return 10;
}
In file a.cc,
#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
try
{
bar1();
}
catch(int64_t x)
{
printf("good %ld", x);
}
}
int main(int argc, char *argv[])
{
foo();
return 0;
}
To compile it:
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
Output
good 1976
https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html has more detail info about __cxa_throw
.
I am not sure whether it is portable or not, and I test it with ‘gcc-4.8.2’ on Linux.
answered Jun 30, 2014 at 10:41
wcywcy
87511 silver badges12 bronze badges
4
This question is super old, but I just stumbled across it and thought I’d share a technique: divide by zero, or dereference a null pointer.
The question is simply «how to throw», not how to catch, or even how to throw a specific type of exception. I had a situation ages ago where we needed to trigger an exception from C to be caught in C++. Specifically, we had occasional reports of «pure virtual function call» errors, and needed to convince the C runtime’s _purecall function to throw something. So we added our own _purecall function that divided by zero, and boom, we got an exception that we could catch on C++, and even use some stack fun to see where things went wrong.
answered Mar 28, 2014 at 14:00
JoeJoe
3,8271 gold badge26 silver badges37 bronze badges
2
On Windows with Microsoft Visual C++ (MSVC) there’s __try ... __except ...
, but it’s really horrible and you don’t want to use it if you can possibly avoid it. Better to say that there are no exceptions.
answered May 23, 2010 at 12:54
Donal FellowsDonal Fellows
133k18 gold badges149 silver badges215 bronze badges
3
C doesn’t have exceptions.
There are various hacky implementations that try to do it (one example at: http://adomas.org/excc/).
answered May 23, 2010 at 12:49
JoeJoe
41.5k20 gold badges104 silver badges125 bronze badges
As mentioned in numerous threads, the «standard» way of doing this is using setjmp/longjmp. I posted yet another such solution to https://github.com/psevon/exceptions-and-raii-in-c
This is to my knowledge the only solution that relies on automatic cleanup of allocated resources. It implements unique and shared smartpointers, and allows intermediate functions to let exceptions pass through without catching and still have their locally allocated resources cleaned up properly.
answered Apr 8, 2014 at 16:21
C doesn’t support exceptions. You can try compiling your C code as C++ with Visual Studio or G++ and see if it’ll compile as-is. Most C applications will compile as C++ without major changes, and you can then use the try… catch syntax.
answered May 23, 2010 at 12:50
Mahmoud Al-QudsiMahmoud Al-Qudsi
28.4k12 gold badges87 silver badges125 bronze badges
answered Oct 1, 2020 at 8:15
alinsoaralinsoar
15.4k4 gold badges57 silver badges74 bronze badges
If you write code with the happy path design pattern (for example, for an embedded device) you may simulate exception error processing (AKA deffering or finally emulation) with operator «goto».
int process(int port)
{
int rc;
int fd1;
int fd2;
fd1 = open("/dev/...", ...);
if (fd1 == -1) {
rc = -1;
goto out;
}
fd2 = open("/dev/...", ...);
if (fd2 == -1) {
rc = -1;
goto out;
}
// Do some with fd1 and fd2 for example write(f2, read(fd1))
rc = 0;
out:
//if (rc != 0) {
(void)close(fd1);
(void)close(fd2);
//}
return rc;
}
It is not actually an exception handler, but it takes you a way to handle error at function exit.
P.S.: You should be careful to use goto only from the same or more deep scopes and never jump a variable declaration.
answered Jul 11, 2019 at 0:08
Vitold S.Vitold S.
4024 silver badges13 bronze badges
1
In C we can’t use try case to handle the error.
but if you can use Windows.h so you can:
#include <stdio.h>
#include <Windows.h>
#include <setjmp.h>
jmp_buf Buf;
NTAPI Error_Handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
printf("co loi roi ban oi.!!!\r\n");
longjmp(Buf, 1);
}
void main()
{
AddVectoredExceptionHandler(1, Error_Handler);
int x = 0;
printf("start main\r\n");
if (setjmp(Buf) == 0)
{
int y = 1 / x;
}
printf("end main\r\n");
}
answered Sep 2, 2021 at 7:41
I typed this into Google, but I only found how-tos in C++.
How can I do it in C?
asked May 23, 2010 at 12:48
httpinterprethttpinterpret
6,4399 gold badges33 silver badges37 bronze badges
3
There are no exceptions in C. In C the errors are notified by the returned value of the function, the exit value of the process, signals to the process (Program Error Signals (GNU libc)) or the CPU hardware interruption (or other notification error form the CPU if there is)(How processor handles the case of division by zero).
Exceptions are defined in C++ and other languages though. Exception handling in C++ is specified in the C++ standard «S.15 Exception handling», there is no equivalent section in the C standard.
answered May 23, 2010 at 12:49
Brian R. BondyBrian R. Bondy
340k124 gold badges596 silver badges636 bronze badges
5
In C you could use the combination of the setjmp()
and longjmp()
functions, defined in setjmp.h
. Example from Wikipedia
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void second(void) {
printf("second\n"); // prints
longjmp(buf,1); // jumps back to where setjmp
// was called - making setjmp now return 1
}
void first(void) {
second();
printf("first\n"); // does not print
}
int main() {
if ( ! setjmp(buf) ) {
first(); // when executed, setjmp returns 0
} else { // when longjmp jumps back, setjmp returns 1
printf("main"); // prints
}
return 0;
}
Note: I would actually advise you not to use them as they work awful with C++ (destructors of local objects wouldn’t get called) and it is really hard to understand what is going on. Return some kind of error instead.
einpoklum
119k57 gold badges342 silver badges691 bronze badges
answered May 23, 2010 at 13:36
5
There’s no built-in exception mechanism in C; you need to simulate exceptions and their semantics. This is usually achieved by relying on setjmp
and longjmp
.
There are quite a few libraries around, and I’m implementing yet another one. It’s called exceptions4c; it’s portable and free. You may take a look at it, and compare it against other alternatives to see which fits you most.
answered Apr 28, 2011 at 18:31
3
Plain old C doesn’t actually support exceptions natively.
You can use alternative error handling strategies, such as:
- returning an error code
- returning
FALSE
and using alast_error
variable or function.
See http://en.wikibooks.org/wiki/C_Programming/Error_handling.
answered May 23, 2010 at 12:50
Lucas JonesLucas Jones
19.8k8 gold badges75 silver badges88 bronze badges
1
C is able to throw C++ exceptions. It is machine code anyway.
For example, in file bar.c:
#include <stdlib.h>
#include <stdint.h>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
int64_t * p = (int64_t*)__cxa_allocate_exception(8);
*p = 1976;
__cxa_throw(p, &_ZTIl, 0);
return 10;
}
In file a.cc,
#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
try
{
bar1();
}
catch(int64_t x)
{
printf("good %ld", x);
}
}
int main(int argc, char *argv[])
{
foo();
return 0;
}
To compile it:
gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out
Output
good 1976
https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html has more detail info about __cxa_throw
.
I am not sure whether it is portable or not, and I test it with ‘gcc-4.8.2’ on Linux.
answered Jun 30, 2014 at 10:41
wcywcy
87511 silver badges12 bronze badges
4
This question is super old, but I just stumbled across it and thought I’d share a technique: divide by zero, or dereference a null pointer.
The question is simply «how to throw», not how to catch, or even how to throw a specific type of exception. I had a situation ages ago where we needed to trigger an exception from C to be caught in C++. Specifically, we had occasional reports of «pure virtual function call» errors, and needed to convince the C runtime’s _purecall function to throw something. So we added our own _purecall function that divided by zero, and boom, we got an exception that we could catch on C++, and even use some stack fun to see where things went wrong.
answered Mar 28, 2014 at 14:00
JoeJoe
3,8271 gold badge26 silver badges37 bronze badges
2
On Windows with Microsoft Visual C++ (MSVC) there’s __try ... __except ...
, but it’s really horrible and you don’t want to use it if you can possibly avoid it. Better to say that there are no exceptions.
answered May 23, 2010 at 12:54
Donal FellowsDonal Fellows
133k18 gold badges149 silver badges215 bronze badges
3
C doesn’t have exceptions.
There are various hacky implementations that try to do it (one example at: http://adomas.org/excc/).
answered May 23, 2010 at 12:49
JoeJoe
41.5k20 gold badges104 silver badges125 bronze badges
As mentioned in numerous threads, the «standard» way of doing this is using setjmp/longjmp. I posted yet another such solution to https://github.com/psevon/exceptions-and-raii-in-c
This is to my knowledge the only solution that relies on automatic cleanup of allocated resources. It implements unique and shared smartpointers, and allows intermediate functions to let exceptions pass through without catching and still have their locally allocated resources cleaned up properly.
answered Apr 8, 2014 at 16:21
C doesn’t support exceptions. You can try compiling your C code as C++ with Visual Studio or G++ and see if it’ll compile as-is. Most C applications will compile as C++ without major changes, and you can then use the try… catch syntax.
answered May 23, 2010 at 12:50
Mahmoud Al-QudsiMahmoud Al-Qudsi
28.4k12 gold badges87 silver badges125 bronze badges
answered Oct 1, 2020 at 8:15
alinsoaralinsoar
15.4k4 gold badges57 silver badges74 bronze badges
If you write code with the happy path design pattern (for example, for an embedded device) you may simulate exception error processing (AKA deffering or finally emulation) with operator «goto».
int process(int port)
{
int rc;
int fd1;
int fd2;
fd1 = open("/dev/...", ...);
if (fd1 == -1) {
rc = -1;
goto out;
}
fd2 = open("/dev/...", ...);
if (fd2 == -1) {
rc = -1;
goto out;
}
// Do some with fd1 and fd2 for example write(f2, read(fd1))
rc = 0;
out:
//if (rc != 0) {
(void)close(fd1);
(void)close(fd2);
//}
return rc;
}
It is not actually an exception handler, but it takes you a way to handle error at function exit.
P.S.: You should be careful to use goto only from the same or more deep scopes and never jump a variable declaration.
answered Jul 11, 2019 at 0:08
Vitold S.Vitold S.
4024 silver badges13 bronze badges
1
In C we can’t use try case to handle the error.
but if you can use Windows.h so you can:
#include <stdio.h>
#include <Windows.h>
#include <setjmp.h>
jmp_buf Buf;
NTAPI Error_Handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
printf("co loi roi ban oi.!!!\r\n");
longjmp(Buf, 1);
}
void main()
{
AddVectoredExceptionHandler(1, Error_Handler);
int x = 0;
printf("start main\r\n");
if (setjmp(Buf) == 0)
{
int y = 1 / x;
}
printf("end main\r\n");
}
answered Sep 2, 2021 at 7:41
One of the advantages of C++ over C is Exception Handling. Exceptions are runtime anomalies or abnormal conditions that a program encounters during its execution. There are two types of exceptions: a)Synchronous, b)Asynchronous (i.e., exceptions which are beyond the program’s control, such as disc failure, keyboard interrupts etc.). C++ provides the following specialized keywords for this purpose:
try: Represents a block of code that can throw an exception.
catch: Represents a block of code that is executed when a particular exception is thrown.
throw: Used to throw an exception. Also used to list the exceptions that a function throws but doesn’t handle itself.
Why Exception Handling?
The following are the main advantages of exception handling over traditional error handling:
1) Separation of Error Handling code from Normal Code: In traditional error handling codes, there are always if-else conditions to handle errors. These conditions and the code to handle errors get mixed up with the normal flow. This makes the code less readable and maintainable. With try/catch blocks, the code for error handling becomes separate from the normal flow.
2) Functions/Methods can handle only the exceptions they choose: A function can throw many exceptions, but may choose to handle some of them. The other exceptions, which are thrown but not caught, can be handled by the caller. If the caller chooses not to catch them, then the exceptions are handled by the caller of the caller.
In C++, a function can specify the exceptions that it throws using the throw keyword. The caller of this function must handle the exception in some way (either by specifying it again or catching it).
3) Grouping of Error Types: In C++, both basic types and objects can be thrown as exceptions. We can create a hierarchy of exception objects, group exceptions in namespaces or classes and categorize them according to their types.
C++ Exceptions:
When executing C++ code, different errors can occur: coding errors made by the programmer, errors due to wrong input, or other unforeseeable things.
When an error occurs, C++ will normally stop and generate an error message. The technical term for this is: C++ will throw an exception (error).
C++ try and catch:
Exception handling in C++ consists of three keywords: try, throw and catch:
The try statement allows you to define a block of code to be tested for errors while it is being executed.
The throw keyword throws an exception when a problem is detected, which lets us create a custom error.
The catch statement allows you to define a block of code to be executed if an error occurs in the try block.
The try and catch keywords come in pairs:
We use the try block to test some code: If the value of a variable “age” is less than 18, we will throw an exception, and handle it in our catch block.
In the catch block, we catch the error if it occurs and do something about it. The catch statement takes a single parameter. So, if the value of age is 15 and that’s why we are throwing an exception of type int in the try block (age), we can pass “int myNum” as the parameter to the catch statement, where the variable “myNum” is used to output the value of age.
If no error occurs (e.g. if age is 20 instead of 15, meaning it will be greater than 18), the catch block is skipped.
Exception Handling in C++
1) The following is a simple example to show exception handling in C++. The output of the program explains the flow of execution of try/catch blocks.
CPP
#include <iostream>
using
namespace
std;
int
main()
{
int
x = -1;
cout <<
"Before try \n"
;
try
{
cout <<
"Inside try \n"
;
if
(x < 0)
{
throw
x;
cout <<
"After throw (Never executed) \n"
;
}
}
catch
(
int
x ) {
cout <<
"Exception Caught \n"
;
}
cout <<
"After catch (Will be executed) \n"
;
return
0;
}
Output:
Before try Inside try Exception Caught After catch (Will be executed)
2) There is a special catch block called the ‘catch all’ block, written as catch(…), that can be used to catch all types of exceptions. For example, in the following program, an int is thrown as an exception, but there is no catch block for int, so the catch(…) block will be executed.
CPP
#include <iostream>
using
namespace
std;
int
main()
{
try
{
throw
10;
}
catch
(
char
*excp) {
cout <<
"Caught "
<< excp;
}
catch
(...) {
cout <<
"Default Exception\n"
;
}
return
0;
}
Output:
Default Exception
3) Implicit type conversion doesn’t happen for primitive types. For example, in the following program, ‘a’ is not implicitly converted to int.
CPP
#include <iostream>
using
namespace
std;
int
main()
{
try
{
throw
'a'
;
}
catch
(
int
x) {
cout <<
"Caught "
<< x;
}
catch
(...) {
cout <<
"Default Exception\n"
;
}
return
0;
}
Output:
Default Exception
4) If an exception is thrown and not caught anywhere, the program terminates abnormally. For example, in the following program, a char is thrown, but there is no catch block to catch the char.
CPP
#include <iostream>
using
namespace
std;
int
main()
{
try
{
throw
'a'
;
}
catch
(
int
x) {
cout <<
"Caught "
;
}
return
0;
}
Output:
terminate called after throwing an instance of 'char' This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
We can change this abnormal termination behavior by writing our own unexpected function.
5) A derived class exception should be caught before a base class exception. See this for more details.
6) Like Java, the C++ library has a standard exception class which is the base class for all standard exceptions. All objects thrown by the components of the standard library are derived from this class. Therefore, all standard exceptions can be caught by catching this type
7) Unlike Java, in C++, all exceptions are unchecked, i.e., the compiler doesn’t check whether an exception is caught or not (See this for details). So, it is not necessary to specify all uncaught exceptions in a function declaration. Although it’s a recommended practice to do so. For example, the following program compiles fine, but ideally the signature of fun() should list the unchecked exceptions.
CPP
#include <iostream>
using
namespace
std;
void
fun(
int
*ptr,
int
x)
{
if
(ptr == NULL)
throw
ptr;
if
(x == 0)
throw
x;
}
int
main()
{
try
{
fun(NULL, 0);
}
catch
(...) {
cout <<
"Caught exception from fun()"
;
}
return
0;
}
Output:
Caught exception from fun()
A better way to write the above code:
CPP
#include <iostream>
using
namespace
std;
void
fun(
int
*ptr,
int
x)
throw
(
int
*,
int
)
{
if
(ptr == NULL)
throw
ptr;
if
(x == 0)
throw
x;
}
int
main()
{
try
{
fun(NULL, 0);
}
catch
(...) {
cout <<
"Caught exception from fun()"
;
}
return
0;
}
Note : The use of Dynamic Exception Specification has been deprecated since C++11. One of the reasons for it may be that it can randomly abort your program. This can happen when you throw an exception of another type which is not mentioned in the dynamic exception specification. Your program will abort itself because in that scenario, it calls (indirectly) terminate(), which by default calls abort().
Output:
Caught exception from fun()
In C++, try/catch blocks can be nested. Also, an exception can be re-thrown using “throw; “.
CPP
#include <iostream>
using
namespace
std;
int
main()
{
try
{
try
{
throw
20;
}
catch
(
int
n) {
cout <<
"Handle Partially "
;
throw
;
}
}
catch
(
int
n) {
cout <<
"Handle remaining "
;
}
return
0;
}
Output:
Handle Partially Handle remaining
A function can also re-throw a function using the same “throw; ” syntax. A function can handle a part and ask the caller to handle the remaining.
9) When an exception is thrown, all objects created inside the enclosing try block are destroyed before the control is transferred to the catch block.
CPP
#include <iostream>
using
namespace
std;
class
Test {
public
:
Test() { cout <<
"Constructor of Test "
<< endl; }
~Test() { cout <<
"Destructor of Test "
<< endl; }
};
int
main()
{
try
{
Test t1;
throw
10;
}
catch
(
int
i) {
cout <<
"Caught "
<< i << endl;
}
}
Output:
Constructor of Test Destructor of Test Caught 10
10) You may like to try Quiz on Exception Handling in C++.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Последнее обновление: 30.12.2021
Обычно система сама генерирует исключения при определенных ситуациях, например, при делении числа на ноль. Но язык C#
также позволяет генерировать исключения вручную с помощью оператора throw. То есть с помощью
этого оператора мы сами можем создать исключение и вызвать его в процессе выполнения.
Например, в нашей программе происходит ввод имени пользователя, и мы хотим, чтобы, если длина имени меньше 2 символов, то
возникало исключение:
try { Console.Write("Введите имя: "); string? name = Console.ReadLine(); if (name== null || name.Length < 2) { throw new Exception("Длина имени меньше 2 символов"); } else { Console.WriteLine($"Ваше имя: {name}"); } } catch (Exception e) { Console.WriteLine($"Ошибка: {e.Message}"); }
После оператора throw указывается объект исключения, через конструктор которого мы можем передать сообщение
об ошибке. Естественно вместо типа Exception мы можем использовать объект любого другого типа исключений.
Затем в блоке catch сгенерированное нами исключение будет обработано.
Подобным образом мы можем генерировать исключения в любом месте программы. Но существует также и другая форма
использования оператора throw, когда после данного оператора не указывается объект исключения. В подобном виде оператор throw
может использоваться только в блоке catch:
try { try { Console.Write("Введите имя: "); string? name = Console.ReadLine(); if (name == null || name.Length < 2) { throw new Exception("Длина имени меньше 2 символов"); } else { Console.WriteLine($"Ваше имя: {name}"); } } catch (Exception e) { Console.WriteLine($"Ошибка: {e.Message}"); throw; } } catch (Exception ex) { Console.WriteLine(ex.Message); }
В данном случае при вводе имени с длиной меньше 2 символов возникнет исключение, которое будет обработано внутренним блоком catch.
Однако поскольку в этом блоке используется оператор throw, то исключение будет передано дальше внешнему блоку catch, который получит то же самое исключение и выведет то же самое сообщение на консоль.
Signals an erroneous condition and executes an error handler.
Contents
- 1 Syntax
- 2 Explanation
- 3 The exception object
- 4 Stack unwinding
- 5 Notes
- 6 Keywords
- 7 Example
- 8 Defect reports
- 9 See also
[edit] Syntax
throw expression
|
(1) | |
throw
|
(2) | |
[edit] Explanation
- See try-catch block for more information about try and catch (exception handler) blocks
1) First, copy-initializes the exception object from expression
|
(since C++11) |
|
(since C++17) |
- The copy/move (since C++11) may be subject to copy elision
- then transfers control to the exception handler with the matching type for which the compound statement or member initializer list that follows the keyword try was most recently entered and not exited by this thread of execution.
2) Rethrows the currently handled exception. Abandons the execution of the current catch block and passes control to the next matching exception handler (but not to another catch clause after the same try block: its compound-statement is considered to have been ‘exited’), reusing the existing exception object: no new objects are made. This form is only allowed when an exception is presently being handled (it calls std::terminate if used otherwise). The catch clause associated with a function-try-block must exit via rethrowing if used on a constructor.
See std::terminate and std::unexpected (until C++17) for the handling of errors that arise during exception handling.
[edit] The exception object
The exception object is a temporary object in unspecified storage that is constructed by the throw
expression.
The type of the exception object is the static type of expression with top-level cv-qualifiers removed. Array and function types are adjusted to pointer and pointer to function types, respectively. If the type of the exception object would be an incomplete type, an abstract class type, or pointer to incomplete type other than pointer to (cv-qualified) void, the throw-expression is a compile-time error. If the type of expression is a class type, its copy/move (since C++11) constructor and destructor must be accessible even if copy elision takes place.
Unlike other temporary objects, the exception object is considered to be an lvalue argument when initializing the catch clause parameters, so it can be caught by lvalue reference, modified, and rethrown.
The exception object persists until the last catch clause exits other than by rethrowing (if not by rethrowing, it is destroyed immediately after the destruction of the catch clause’s parameter), or until the last std::exception_ptr that references this object is destroyed (in which case the exception object is destroyed just before the destructor of std::exception_ptr returns.
[edit] Stack unwinding
Once the exception object is constructed, the control flow works backwards (up the call stack) until it reaches the start of a try block, at which point the parameters of all associated catch
blocks are compared, in order of appearance, with the type of the exception object to find a match (see try-catch for details on this process). If no match is found, the control flow continues to unwind the stack until the next try
block, and so on. If a match is found, the control flow jumps to the matching catch
block.
As the control flow moves up the call stack, destructors are invoked for all objects with automatic storage duration that are constructed, but not yet destroyed, since the corresponding try-block was entered, in reverse order of completion of their constructors. If an exception is thrown from a destructor of a local variable or of a temporary used in a return statement, the destructor for the object returned from the function is also invoked.
If an exception is thrown from a constructor or (rare) from a destructor of an object (regardless of the object’s storage duration), destructors are called for all fully-constructed non-static non-variant members and base classes, in reverse order of completion of their constructors. Variant members of union-like classes are only destroyed in the case of unwinding from constructor, and if the active member changed between initialization and destruction, the behavior is undefined.
If a delegating constructor exits with an exception after the non-delegating constructor successfully completed, the destructor for this object is called. |
(since C++11) |
If the exception is thrown from a constructor that is invoked by a new-expression, the matching deallocation function is called, if available.
This process is called stack unwinding.
If any function that is called directly by the stack unwinding mechanism, after initialization of the exception object and before the start of the exception handler, exits with an exception, std::terminate is called. Such functions include destructors of objects with automatic storage duration whose scopes are exited, and the copy constructor of the exception object that is called (if not elided) to initialize catch-by-value arguments.
If an exception is thrown and not caught, including exceptions that escape the initial function of std::thread, the main function, and the constructor or destructor of any static or thread-local objects, then std::terminate is called. It is implementation-defined whether any stack unwinding takes place for uncaught exceptions.
[edit] Notes
When rethrowing exceptions, the second form must be used to avoid object slicing in the (typical) case where exception objects use inheritance:
try { std::string("abc").substr(10); // throws std::out_of_range } catch (const std::exception& e) { std::cout << e.what() << '\n'; // throw e; // copy-initializes a new exception object of type std::exception throw; // rethrows the exception object of type std::out_of_range }
The throw-expression is classified as prvalue expression of type void. Like any other expression, it may be a sub-expression in another expression, most commonly in the conditional operator:
[edit] Keywords
throw
[edit] Example
#include <iostream> #include <stdexcept> struct A { int n; A(int n = 0): n(n) { std::cout << "A(" << n << ") constructed successfully\n"; } ~A() { std::cout << "A(" << n << ") destroyed\n"; } }; int foo() { throw std::runtime_error("error"); } struct B { A a1, a2, a3; B() try : a1(1), a2(foo()), a3(3) { std::cout << "B constructed successfully\n"; } catch(...) { std::cout << "B::B() exiting with exception\n"; } ~B() { std::cout << "B destroyed\n"; } }; struct C : A, B { C() try { std::cout << "C::C() completed successfully\n"; } catch(...) { std::cout << "C::C() exiting with exception\n"; } ~C() { std::cout << "C destroyed\n"; } }; int main () try { // creates the A base subobject // creates the a1 member of B // fails to create the a2 member of B // unwinding destroys the a1 member of B // unwinding destroys the A base subobject C c; } catch (const std::exception& e) { std::cout << "main() failed to create C with: " << e.what(); }
Output:
A(0) constructed successfully A(1) constructed successfully A(1) destroyed B::B() exiting with exception A(0) destroyed C::C() exiting with exception main() failed to create C with: error
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 499 | C++98 | an array with unknown bound could not be thrown because its type is incomplete, but an exception object can be created from the decayed pointer without any problem |
apply the type completion requirement to the exception object instead |
CWG 668 | C++98 | std::terminate was not called if an exception is thrown from the destructor of a local non-automatic object |
call std::terminate in this case |
CWG 1863 | C++11 | copy constructor was not required for move-only exception objects when thrown, but copying allowed later |
copy constructor required |
CWG 1866 | C++98 | variant members were leaked on stack unwinding from constructor | variant members destroyed |
CWG 2176 | C++98 | throw from a local variable destructor could skip return value destructor |
function return value added to unwinding |
[edit] See also
- copy elision
- try-catch block
-
noexcept
specifier - dynamic exception specifications