Reputation: 1964
I have written the below code...
#include <iostream>
using namespace std;
struct Error {
Error() { cout << "Constructor called\n"; }
Error(const Error&) { cout << "Copy Constructor called\n"; }
};
void test() {
throw Error();
}
int main() {
try {
test();
}
catch (Error e) {
}
}
I am getting the following output on C++17 and later...
Constructor called
Copy Constructor called
Even the C++17 Guaranteed copy elision says "Copy elision is mandatory in Throwing and catching exceptions by value"
. I am getting the "Copy Constructor called"
as output.
Am I missing something?
Upvotes: 2
Views: 134
Reputation: 38862
Copy elision is mandatory in Throwing and catching exceptions by value
Honestly, this is not mandatory, see below, and this works as expected - when test()
is called, a compiler reserves a memory where Error
will be constructed if test()
throws an exception. Until C++17, it could create Error
and copy it to that reserved storage.
The copy, that you observe, is done here: catch (Error e)
- Error
is copied from that reserved storage to a function local argument. Until C++17, the output could be
Constructor called
Copy Constructor called
Copy Constructor called
If you don't want to copy an object, fix it: catch (Error &e)
or catch (const Error &e)
.
#include <iostream>
struct Error {
Error() { std::cout << "Constructor called\n"; }
Error(const Error &) { std::cout << "Copy Constructor called\n"; }
};
void test() { throw Error(); }
int main() {
try {
test();
} catch (const Error &e) {
}
}
// Output since C++17:
// Constructor called
//
// Possible output until C++17:
// Constructor called
// Copy Constructor called
the copy-initialization of
o
can be omitted by treating the exception-declaration as an alias
The standard is saying that catch (Error e)
can be treated as catch (Error &e)
. Note, can is not must.
Upvotes: 7