不在异常中嵌入std::字符串的规则是否仍然适用于move构造函数
Does rule of not embedding std::string in exceptions still hold with move constructors?
我之前听说不应该创建具有std::string
类型字段的异常类。Boost网站就是这么说的。其原理是,如果内存分配失败,std::string
复制构造函数可以抛出异常,如果在捕获当前处理的异常之前抛出异常,则程序将终止。
然而,它仍然适用于移动构造函数的世界吗?抛出异常时,不会使用move构造函数而不是copy构造函数吗?我是否正确地理解,使用C++11将不会进行内存分配,不存在异常的可能性,并且std::string
现在在异常类中绝对可以?
答案是:
是的,您仍然不希望在异常类型中嵌入std::string
。例外情况经常被复制,有时是在你不知情的情况下。例如,在一些平台上,std::rethrow_exception
将复制异常(在某些平台上则不会(。
为了获得最佳实践,请保留副本构造函数noexcept
。
然而,并没有失去一切。一个鲜为人知的事实是,C++在标准中总是有一个不可变的ref计数字符串类型(带有非抛出复制构造函数(,只是有一个模糊的名称。实际上有两个名字:
logic_error
runtime_error
这些类型的规范必须包含一个不可变的ref计数字符串类对象。嗯,不是完全一成不变的。可以用赋值替换字符串。但是您不能在其他地方修改字符串。
我的建议是从其中一种类型派生,或者如果这是不可接受的,则嵌入其中一种,并将其视为不可变的ref计数字符串类型:
#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>{}, "");
抛出异常时是否制作string
的副本取决于catch
块。
举个例子:
#include <iostream>
struct A
{
};
void foo()
{
throw A();
}
void test1()
{
try
{
foo();
}
catch (A&& a)
{
}
}
void test2()
{
try
{
foo();
}
catch (A const& a)
{
}
}
void test3()
{
try
{
foo();
}
catch (A a)
{
}
}
int main()
{
test1();
test2();
test3();
}
您不会在test1
或test2
中复制A
,但最终会在test3
中复制。
相关文章:
- 此代码是否违反一个定义规则
- antlr 规则上下文是否可以独立于目标
- C++ 用于检查容器类中是否存在函数和隐式推导规则的概念
- 强制转换为不相关的引用类型是否违反严格的别名规则?
- 是否有可能编写新的叮当声现代化规则?
- 在 decltype(auto) 的情况下,lambda 是否有特殊规则?
- C++20 中的严格别名规则是否允许标准 c++ unicode 字符和下划线类型之间"reinterpret
- 是否使用示波器队列:: swap违反任何规则来清空std ::队列
- 严格别名规则是否适用于跨函数调用
- MISRA C++(规则 18-4-1)和动态内存分配 - 是否允许 std::string
- c++11 严格别名规则是否允许通过 char *、char(&)[N],甚至 std::array<char、N> 和 -fstrict-aliasing -Wstrict-aliasi
- 此constexpr虚拟功能技术是否违反了任何C 11/C 14规则
- 本地类规则是否与c++14返回类型推导一致
- 从标准库重新定义函数是否违反了一个定义规则
- 已签名/未签名的别名规则是否按预期工作
- 将字符阵列施放到另一种类型中是否违反了严格的确定规则
- 是否使用“ __Date__”或“ __Time__”违反了一个定义规则
- 这是否违反了严格的锯齿或指针对齐规则
- 是否违反 C/C++ 运算符优先级和关联性规则?
- 哪些规则确定对象是否易于复制