Ron*_*urk 3 c++ stl exception-handling unique-ptr
我已经开始使用C++ 11,特别是使用unique_ptr来使代码异常安全且所有权更具可读性.这通常很有效,直到我想抛出unique_ptr.我有错误代码(抛出许多地方,陷入一个地方),创建复杂的状态.由于逻辑上动态分配的内存的所有权正从thrower传递到catcher,所以unique_ptr似乎是适当的类型来表示并明确catcher已经获得了一个堆对象.没有工作,至少使用免费的Visual Studio 2013.这是一个简化的代码示例,它不再像任何有用的东西,但会引发行为:
// cl /nologo /EHsc /W4 test1.cpp
#include <memory>
using std::unique_ptr;
class IError
{
public:
virtual ~IError() {};
virtual void DoStuff();
};
unique_ptr<IError> Error();
int Foo() { throw Error(); }
int main(void)
{
try {
Foo();
}
catch(unique_ptr<IError> Report)
{
Report->DoStuff();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
并且编译器如此喷出:
test1.cpp
test1.cpp(13) : warning C4673: throwing 'std::unique_ptr<IError,std::default_delete<_Ty>>' the following types will n
ot be considered at the catch site
with
[
_Ty=IError
]
test1.cpp(13) : warning C4670: '_Unique_ptr_base<class IError,struct std::default_delete<class IError>,1>' : this bas
e class is inaccessible
test1.cpp(13) : error C2280: 'std::unique_ptr<IError,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,
std::default_delete<_Ty>> &)' : attempting to reference a deleted function
with
[
_Ty=IError
]
C:\bin\Visual Studio Express 2013\VC\INCLUDE\memory(1486) : see declaration of 'std::unique_ptr<IError,std::d
efault_delete<_Ty>>::unique_ptr'
with
[
_Ty=IError
]
Run Code Online (Sandbox Code Playgroud)
我哪里做错了?
小智 5
作为替代我将使用Rextester具有MSVC版本18.00.21005.1.对于GCC 4.8.1和Clang 3.5,我将使用Coliru.现在,最初在给出一个仓促的答案时,我说unique_ptrs不能被复制,所以你应该通过引用来捕捉它们.但是,当您在MSVC中抛出对象时,似乎会发生错误.所以上述建议仅适用于GCC和Clang.
catch(unique_ptr<IError>& Report)
Run Code Online (Sandbox Code Playgroud)
似乎他们在MSVC如何处理复制/移动省略和/或移动语义方面存在差异,我在C++方面的表现还不够明确,但让我们展示一些可编译的例子.首先是一个带有删除的复制构造函数的基本结构:
#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)
{
}
}
Run Code Online (Sandbox Code Playgroud)
无论优化级别如何,对于GCC和Clang都没有输出,除非你还添加-fno-elide-constructors到调用中,我们看到它们都调用了移动构造函数.对于MSVC,我们收到此错误:
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'
Run Code Online (Sandbox Code Playgroud)
有关更复杂的示例,请参阅投掷可移动对象.问题是两年了但我们观察到相同的行为,GCC和Clang在某些情况下都调用移动构造函数,但MSVC在所有情况下都调用复制构造函数(GCC和Clang在该Throw with object not about to die anyhow (enter non-zero integer部分不同).
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
~
Run Code Online (Sandbox Code Playgroud)
TL; DR GCC和Clang将编译它,但MSVC不会.一个糟糕的解决方法是抛出一个指针:
throw new unique_ptr<IError>;
catch(unique_ptr<IError>* Report);
Run Code Online (Sandbox Code Playgroud)