type
status
date
slug
summary
tags
category
icon
password
Exceptions and Stack Unwinding in C++
In C++, stack unwinding is a key part of handling exceptions. When an exception is thrown, the C++ runtime starts to find the right code to handle it. During this, it goes back through the call stack, which is what we call stack unwinding.
Here’s how it works:
- Throwing an Exception: When an expression or function call throws an exception, the C++ runtime starts to look for code to handle this exception.
- Finding a Handler: The runtime moves up the call stack to find a
catch
block that can deal with the exception.
- Destructing Objects: While moving back, it destroys all local objects on the stack by calling their destructors. This step is crucial because it ensures proper resource release, like freeing memory or closing files.
- Handling the Exception: Once a suitable
catch
block is found, control is transferred to it to start dealing with the exception.
A key feature of stack unwinding is that it always calls the destructors of local objects, helping to prevent resource leaks. This is an important advantage of C++’s exception handling and part of the RAII (Resource Acquisition Is Initialization) principle.
It’s important to note that if an exception is thrown in a destructor and not handled inside it, the program will terminate. This is because the C++ standard doesn’t allow another exception to be thrown during stack unwinding.
Therefore, in C++, when running functions that might throw exceptions, it’s crucial to ensure that the stack is always in a state ready for unwinding. When a function is marked
noexcept
, it means it promises not to throw exceptions. In this case, the compiler doesn’t need to prepare for stack unwinding, reducing extra code generation and improving runtime efficiency.Strong Exception Safety and Move Semantics
- C++98 Standard:
- Memory Transfer Method: For
std::vector
orstd::deque
to expand their size, elements are copied from the old memory to the new, then destroyed in the old memory. - Exception Safety: This method allows
push_back
to provide strong exception safety. Even if an exception occurs during copying, the original elements in thevector
remain intact in the old memory.
- C++11 and Later:
- Introducing Move Semantics: A natural optimization is replacing the copying of
std::vector
elements with move operations, which is usually faster. - Challenges to Strong Exception Safety: Using move semantics in all cases can break the strong exception safety of
push_back
. For example, if n elements are successfully moved to new memory but an exception occurs while moving the n+1 element, the moved elements in the old memory are compromised due to the nature of move semantics. noexcept
and Optimization: Therefore,std::vector
uses move semantics for resizing only when the elements’ move constructors are declared asnoexcept
. This ensures no exceptions are thrown during the move, maintaining the strong exception safety ofpush_back
.
takeaways
- Be Careful When Making a Function
noexcept
- Don't change how a function works just to add
noexcept
. Using return codes instead of exceptions can make your code harder to handle and maintain.
- Automatic
noexcept
in C++11 - In C++11, all functions that free up memory and all destructors are
noexcept
by default. This is a built-in feature of the language standard.
noexcept
is Important for How Functions are Used- When you mark a function as
noexcept
, it tells other parts of your code that this function won’t throw exceptions. This is important because other functions might rely on this behavior.
noexcept
Functions are Easier to Optimize- Functions with
noexcept
can be optimized better by the compiler. This is because the compiler knows these functions won’t cause any unexpected stops due to exceptions.
noexcept
is Great for Certain Operationsnoexcept
is really useful for operations like moving data, swapping, freeing memory, and destructing objects. It makes these operations safer and can improve performance.
- Most Functions Don’t Say
noexcept
Directly - Many functions are neutral about exceptions. They don't throw exceptions themselves, but they might call other functions that do. So, it's not always right to label these as
noexcept
.
- 作者:Zack Yang
- 链接:https://zackyang.blog/article/cpp-noexcept-keyword
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章