c++language-lawyer

Who catches exceptions from copy-constructor in return statement (C++)?


Suppose I have a function returning by value

S f(); 

and I call it like that:

auto s = f();

If copy-constructor of S throws, and return some_s; inside f is surrounded by try-catch block, is it guaranteed that the exception will be captured inside f rather than being thrown on the call site?

I realize that auto s = f(); is subject to mandatory copy elision as of C++17, so there is (at most) one call to copy-constructor of S. But is it guaranteed to happen inside f from the point of view of exception handling?

Tests in gcc, clang, mingw and msvc indicate that this is indeed so (the code is below). What bothers me is that

In any case, some quotes from the standard will be appreciated ;)

Here is the code I used for testing

#include<iostream>
    
struct S{
    S(const S &){
       throw "Oops";
    }
    
    S(int) noexcept  {}
};

S f(){
   
   static/*to avoid RVO*/ S stat(7);
   
   try{
      return stat;
   }catch(const char *what){
      std::cerr << "still in function after failed-return" << std::endl;
   }
   
   return S(7);// mandatory copy-elision (c++17); 
}

int main()
try{
   auto s = f();// mandatory copy-elision (c++17); 
 
}catch(...){
   std::cerr << "Exception from main..." << std::endl;
}

Solution

  • Since C++17, there isn't a copy after f returns. The return value of f is an unmaterialised temporary value, which is materialised in the initialisation of s, it isn't an object, and doesn't need to be copied to initialise something.

    It is not "mandatory copy elision". The lifetime rules were changed such that there isn't an object (yet).

    it seems odd that return does not actually transfer control out of a function

    You can have arbitrarily complex sub-expressions in a return statement, which can throw. If they do, you are allowed to catch them within the function. It would be highly inconvenient if you couldn't.