不久前,我听说我不应该创建具有std::string
类型字段的异常类。那就是Boost网站所说的。基本原理是,std::string
如果内存分配失败,则复制构造函数可以引发异常,并且如果在捕获当前处理的异常之前引发了异常,则程序将终止。
但是,它仍然在move构造函数世界中适用吗?抛出异常时,是否会使用move构造函数而不是copy构造函数?我是否正确理解在C ++ 11中不会发生内存分配,不存在异常的机会,并且std::string
现在在异常类中绝对可以吗?
答案是:
是的,您仍然不想将a嵌入std::string
到异常类型中。异常经常被复制,有时在您不知情的情况下。例如,在某些平台std::rethrow_exception
上将复制异常(在某些平台上则不会)。
为了获得最佳实践,请保留复制构造函数noexcept
。
但是,一切并没有丢失。一个鲜为人知的事实是,C ++在标准中始终具有不可变的ref-counted字符串类型(具有非抛出复制构造函数),只是名称混淆。实际上有两个名字:
logic_error
runtime_error
这些类型的规范必须包含一个不变的引用计数的类似字符串的对象。好吧,不是完全不变的。您可以将字符串替换为赋值。但是您不能以其他方式在适当位置修改字符串。
我的建议是从这些类型之一派生,或者如果不能接受,则嵌入这些类型之一并将其视为不可变的ref-counted字符串类型:
#include <stdexcept>
#include <iostream>
class error1
: public std::runtime_error
{
using msg_ = std::runtime_error;
public:
explicit error1(std::string const& msg)
: msg_(msg)
{}
};
class error2
{
std::runtime_error msg_;
public:
explicit error2(std::string const& msg)
: msg_(msg)
{}
char const* what() const noexcept {return msg_.what();}
};
void
test_error1()
{
try
{
throw error1("test1");
}
catch (error1 const& e)
{
std::cout << e.what() << '\n';
}
}
void
test_error2()
{
try
{
throw error2("test2");
}
catch (error2 const& e)
{
std::cout << e.what() << '\n';
}
}
int
main()
{
test_error1();
test_error2();
}
std :: lib将为您处理所有的字符串处理和内存管理,并且您可以noexcept
讨价还价进行复制:
static_assert(std::is_nothrow_copy_constructible<error1>{}, "");
static_assert(std::is_nothrow_copy_assignable <error1>{}, "");
static_assert(std::is_nothrow_copy_constructible<error2>{}, "");
static_assert(std::is_nothrow_copy_assignable <error2>{}, "");
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句