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:
  1. Throwing an Exception: When an expression or function call throws an exception, the C++ runtime starts to look for code to handle this exception.
  1. Finding a Handler: The runtime moves up the call stack to find a catch block that can deal with the exception.
  1. 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.
  1. 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

  1. C++98 Standard:
      • Memory Transfer Method: For std::vector or std::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 the vector remain intact in the old memory.
  1. 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 as noexcept. This ensures no exceptions are thrown during the move, maintaining the strong exception safety of push_back.
 

 

takeaways

  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. noexcept is Great for Certain Operations
      • noexcept is really useful for operations like moving data, swapping, freeing memory, and destructing objects. It makes these operations safer and can improve performance.
  1. 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.
 
OpenGL Basics (1): Brief Overviewdeleted functions
Zack Yang
Zack Yang
Just a humble bounty hunter🥷
公告
type
status
date
slug
summary
tags
category
icon
password
Hey there, welcome to my blog 👋
-- 这个博客写些什么 --
定期技术分享🤖
不定期发疯文学🤡