As a surrogate I'll be using Rextester which has MSVC version 18.00.21005.1. For GCC 4.8.1 and Clang 3.5, I'll be using Coliru. Now, initially when giving a hasty answer, I said that unique_ptr
s cannot be copied and so you should be catching them by reference. However it appears the error occurs when you throw the object in MSVC. So the above advice will only apply to GCC and Clang.
catch(unique_ptr<IError>& Report)
It appears that they differ in how MSVC handles copy/move elision and/or move semantics, I'm not good enough at C++ to be more specific than that, but let's show some compilable examples. First a basic struct with a deleted copy constructor:
#include <iostream>
struct D {
D() {};
D(const D& other) = delete;
D(D&& other) { std::cout << "call D move constructor... \n"; }
};
int main()
{
try {
throw D();
} catch(D const& d)
{
}
}
Regardless of optimization level, for both GCC and Clang, no output unless you also add -fno-elide-constructors
to the invocation and we see that they both call the move constructor. For MSVC, we get this error:
source_file.cpp(22) : error C2280: 'D::D(const D &)' : attempting to reference a deleted function
source_file.cpp(7) : see declaration of 'D::D'
For a more complicated example, see Throwing movable objects. The question is two years old yet we observe the same behavior in that GCC and Clang both call the move constructor in certain situations but MSVC calls the copy constructor in all situations (GCC and Clang differ for the Throw with object not about to die anyhow (enter non-zero integer
part.)
Throw directly:
C
caught: 007FFA7C
~
Throw with object about to die anyhow
C
c
~
caught: 007FFA74
~
Throw with object not about to die anyhow (enter non-zero integer)
C
c
caught: 007FFA70
~
1
~
TL;DR GCC and Clang will compile it but MSVC won't. A crappy workaround is to throw a pointer instead:
throw new unique_ptr<IError>;
catch(unique_ptr<IError>* Report);