This behavior is correct, it is called copy elision/move elision.
https://en.cppreference.com/w/cpp/language/copy_elision
From: Std-Discussion <std-discussion-bounces@lists.isocpp.org>
On Behalf Of Brian Bi via Std-Discussion
Sent: Friday, September 20, 2019 12:36 PM
To: std-discussion@lists.isocpp.org
Cc: Brian Bi <bbi5291@gmail.com>
Subject: [std-discussion] Is the standard clear enough about throwing exceptions from functions that return prvalues?
|
*External Message* - Use caution before opening links or attachments |
In the following program, no prvalue materialization conversion should occur. Instead,
s should just be value-initialized:
#include <iostream>
struct S {
S() { throw 42; }
S(S&&) { std::cout << "I am nontrivial" << std::endl; }
};
S foo() {
try {
return {};
} catch (int) {
std::cout << "caught by foo\n";
throw;
}
}
int main() {
try {
S s = foo();
} catch (int) {
std::cout << "caught by main\n";
}
}
Therefore, I would expect that the constructor of
S should be called in the context of the definition of
s, and foo should not have the opportunity to catch the exception. Put another way, conceptually, the last thing
foo() does before it returns is to create a prvalue that says to value-initialize the
S object (whenever that might finally be required); it doesn't get to actually call the constructor.
Yet GCC and Clang both give
foo the opportunity to catch the exception, as if the constructor call were being done in the context of
foo. http://coliru.stacked-crooked.com/a/ae2943b361ab51a9
Is the standard clear enough that the behaviour of GCC and Clang in this case is actually the intended behaviour? I think that it is not clear.
--
Brian Bi