提问人:metablaster 提问时间:10/19/2019 最后编辑:metablaster 更新时间:10/20/2019 访问量:202
派生自 std::exception 的类的赋值运算符
assignment operator for class derived from std::exception
问:
我从中派生了一个自定义异常类std::runtime_error
静态分析器给我一个警告,如果我定义或删除默认操作(复制 ctors、复制/移动运算符、析构函数等),我应该定义或删除它们。
为了解决这个愚蠢的警告,我编写了缺少的赋值运算符,但后来我收到了另一个警告,现在我的运算符隐藏了基本的非虚拟赋值运算符!
由于基类具有我无法复制的私有成员,因此看起来唯一的解决方案是直接为基本对象部分调用基本委托运算符,然后复制对象的其余部分并最终返回*this
*this
但在这样做之前,我看了一下底座的作用以及它的样子:operator=
exception& operator=(exception const& _Other) noexcept
{
if (this == &_Other)
{
return *this;
}
__std_exception_destroy(&_Data);
__std_exception_copy(&_Other._Data, &_Data);
return *this;
}
private:
__std_exception_data _Data;
};
现在知道这是我的实现(带有注释)来调用基本委托并复制派生对象的其余部分:
class Exception :
public std::runtime_error
{
public:
// ...
Exception& operator=(const Exception& other)
{
if (this == &other)
{
return *this;
}
// first copy only base class data to *this
*dynamic_cast<std::runtime_error*>(this) =
runtime_error::operator=(
*dynamic_cast<std::runtime_error*>(
const_cast<Exception*>(&other)));
// then copy derived class data to *this
mInfo = other.mInfo;
mCode = other.mCode;
// finally return complete copy
return *this;
}
private:
std::error_code mCode;
std::string mInfo;
};
这是正确的方法吗?我认为这看起来很麻烦,但我不确定。
编辑
以下是完整的课程,供参考:
#pragma warning (disable : 4275) // base needs to have DLL interface
class ERROR_API Exception :
public std::runtime_error
{
public:
~Exception() noexcept; // cant be inlined in release build
// default/delete
Exception(const Exception&) = default;
Exception(Exception&&) = delete;
Exception& operator=(const Exception& other)
{
if (this == &other)
{
return *this;
}
// copy base class data to *this
*dynamic_cast<std::runtime_error*>(this) =
runtime_error::operator=(
*dynamic_cast<std::runtime_error*>(
const_cast<Exception*>(&other)));
// copy derived class data to *this
mInfo = other.mInfo;
mCode = other.mCode;
return *this;
}
Exception& operator=(Exception&&) = delete;
/** Construct from error enum */
template<typename Enum>
Exception(Enum err_enum);
/** Construct from error enum and string*/
template<typename Enum>
Exception(Enum err_enum, String message);
/** Construct from error_code object */
inline Exception(std::error_code err_code);
/** Construct from error_code object and string */
inline Exception(std::error_code err_code, String message);
/** Get error_condidtion name */
inline virtual std::string ConditionName() const;
/** Get error_category name */
inline virtual std::string CategoryName() const;
/** Get error_condition value */
inline virtual int ConditionValue() const noexcept;
/** Get error_condition value */
inline virtual int ErrorValue() const noexcept;
/** Get additional information string passed to constructor */
inline virtual const String& GetInfo() const noexcept;
/** Get error_code object associated with this exception object */
inline virtual const std::error_code& code() const noexcept;
private:
SUPPRESS(4251); // member needs to have DLL interface
std::error_code mCode;
SUPPRESS(4251); // member needs to have DLL interface
String mInfo;
};
#pragma warning (default : 4275) // base needs to have DLL interface
答:
0赞
metablaster
10/19/2019
#1
感谢 Ulrich Eckhardt、Peter 和其他人的精彩评论,以下是我如何让它工作,结果根本没有警告:
class Exception : public std::runtime_error
{
public:
~Exception() noexcept; // can't be inlined in release build (defaulted in source)
// default/delete
Exception(const Exception&) noexcept = default;
Exception(Exception&&) noexcept = default;
Exception& operator=(const Exception&) noexcept = default;
Exception& operator=(Exception&&) noexcept(false) = deault;
// the rest of the code ...
};
评论
0赞
Eljay
10/19/2019
在一个我无法删除 move-assignment 但该类不支持(也不能)支持 move 语义的类中,我只是做了一个直通来抑制静态分析器。我还发表了一条评论,解释了为什么会做坏事,因为这个可怜的灵魂必须维护该代码。Exception& operator=(Exception&& that) noexcept { *this = that; return *this; }
评论
operator=
runtime_error::operator=(other)
operator=()
std::exception
operator=()
throw()
noexcept
operator=()
std::exception
Exception