use*_*087 25 c++ boost exception
我一直在读,我不应该抛出std::string一些或其他类来分配内存.像这里或更重要的是这里的第3点- 不要嵌入std::string对象.
所以现在我正在尝试将boost :: exception插入到我的项目中,我看到了什么:很多字符串.
为什么不提升符合自己的建议?
如果我有不能硬编码的参数,比如在配置文件中安装,我怎样才能将它们放入异常中而不使用std::string?
或者指南是否std::string仅使用std::string尽可能少的指南?我有点困惑......
我做了一些研究.如果我错了,请纠正我.
如果我理解正确,那就是关于抛出期间的分配以及分配的内存发生了什么.因此,如果我在构造函数中分配内存并且无法在异常的析构函数中释放内存,则内存会丢失,这将产生内存泄漏.但是在投掷之前分配它是可以的,所以异常是干净的.
我试过这个:
struct xexception {
int *ttt[10];
xexception() {
ttt[0] = new int[0xfffffffL];
ttt[1] = new int[0xfffffffL];
ttt[2] = new int[0xfffffffL];
ttt[3] = new int[0xfffffffL];
ttt[4] = new int[0xfffffffL];
ttt[5] = new int[0xfffffffL];
ttt[6] = new int[0xfffffffL];
ttt[7] = new int[0xfffffffL];
ttt[8] = new int[0xfffffffL];
ttt[9] = new int[0xfffffffL];
}
~xexception() throw() {
//never happen
delete[] ttt[0];
delete[] ttt[1];
delete[] ttt[2];
delete[] ttt[3];
delete[] ttt[4];
delete[] ttt[5];
delete[] ttt[6];
delete[] ttt[7];
delete[] ttt[8];
delete[] ttt[9];
}
};
int main(int argc, const char *argv[]) {
try {
throw(xexception());
}
catch (const xexception &e) {
std::cerr << "\nttt " << e.ttt[0][0] << std::endl;
}
catch (std::bad_alloc) {
std::cerr << "bad alloc" << std::endl;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果是,我得到bad_alloc和巨大的内存泄漏.
现在如果我之前进行分配,它也会抛出bad_alloc但是在创建异常之前.
异常概念的例外是:
谁在乎?如果我的程序中有bad_alloc,由于memory_leak或其他东西(我在谈论PC上的程序而不是微控制器)我还有其他问题.也许我可以弄清楚发生了bad_alloc,但在哪里?在我的一个函数(一个可能是1000)或者在std::string(我知道它是字符串但是......没有可能操纵字符串的内存......或它消散)的我的alloc .
try {
// where is the error???
int *x = new int[100]; // here?
....
int *y = new int[100]; // or here?
....
int *z = new int[100];
....
int *w = new int[100];
....
int *t = new int[100];
....
int *f = new int[100];
....
std::string str("asdfasdfasdfasdfasdfasdfasdf"); // maybe here
}
catch (the error) {
....
}
Run Code Online (Sandbox Code Playgroud)
然后?我想弄清楚它发生在哪里吗?因此我会使用valgrind而不是例外.
void foo() {
int *i = new int[1];
foo();
}
try {
foo();
}
chatch( bad_boy ) {
go_exception_handler_go(parameters); // oh, shit happens: also an stack_overflow may happend, cause stack is also full
}
Run Code Online (Sandbox Code Playgroud)
或者我应该操纵错误消息并记录它,最终会抛出下一个bad_alloc.
请不要误解我.因为我已经看过boost :: exception我已经重写了我的异常类(直到等待答案),但我也认为没有必要拿起每一粒沙子.
Chr*_*odd 18
该建议基本上告诉您"不要使用任何可能在异常中抛出异常的构造".那是因为如果在尝试抛出异常时遇到异常,C++运行时将立即调用terminate()并终止程序.
现在,如果所涉及的异常中的任何一个只是terminate()反正调用(这是未捕获异常的默认值),那么你真的不需要担心它.例如,如果您的应用程序无法处理bad_alloc(无法从内存中恢复),那么您不必担心std::string可能会抛出它的复制构造函数(例如).
但是,如果您希望能够捕获并从中恢复bad_alloc,则需要确保没有任何异常复制构造函数可以导致一个.如果您正在编写其他应用程序将使用的库,则不应假设该应用程序不想处理bad_alloc.
C++ 11通过尽可能使用移动构造函数(而不是复制构造函数)使这变得更容易.由于移动构造函数std::string永远不会抛出异常,因此std:string只要正确实现移动构造函数并确保使用它们,就可以安全地在异常类型中使用a .请注意,要在throw表达式中抛出的对象的初始构造不是异常抛出过程的一部分,因此构造函数可以抛出异常而不会导致双重异常(和terminate()).所以如果你有:
throw some_function();
Run Code Online (Sandbox Code Playgroud)
some_function可能会抛出异常(例如bad_alloc)而不返回要抛出的对象,这很好.如果它没有抛出异常(并返回一个有效的对象),那么异常类型的移动构造函数将被用于异常抛出过程(如果可用),并且该移动构造函数不能抛出异常.
完全独立于上述情况,无论何时打电话,new您都需要确保delete在每种情况下都能确切地调用一个位置,否则您将泄漏内存(或双重删除时崩溃).只要你有一个函数调用new然后做一些可能引发异常的事情(比如new再次调用),这就变得很棘手.如果在构造函数中发生这种情况,则不会调用该对象的析构函数(虽然基类和字段的析构函数将是),因此您不能像在尝试使用示例那样在析构函数中进行清理.
幸运的是std::unique_ptr存在使这更容易.如果您将异常类编写为:
struct xexception {
std::unique_ptr<int[]> ttt[10];
xexception() {
ttt[0].reset(new int[0xfffffffL]);
ttt[1].reset(new int[0xfffffffL]);
ttt[2].reset(new int[0xfffffffL]);
ttt[3].reset(new int[0xfffffffL]);
ttt[4].reset(new int[0xfffffffL]);
ttt[5].reset(new int[0xfffffffL]);
ttt[6].reset(new int[0xfffffffL]);
ttt[7].reset(new int[0xfffffffL]);
ttt[8].reset(new int[0xfffffffL]);
ttt[9].reset(new int[0xfffffffL]);
}
};
Run Code Online (Sandbox Code Playgroud)
它应该工作,而不是泄漏记忆.
虽然我认为不是std::string用于核心,但基本的例外可能是一个很好的指导方针,我不认为面向用户的库/应用程序必然会遵循这一点.
可能还有其他原因,但您可以点击主要原因:您希望向用户(或开发人员)指出上下文有意义的信息,而这些信息通常只能用文字字符串来完成.必须进行动态分配才能执行此操作.如果由于某种原因,你有一个bad_alloc,你可能已经开始使用,所以它不会购买/失去任何东西.
编辑:
顺便说一句:析构函数std::exception被标记为虚拟的原因!
| 归档时间: |
|
| 查看次数: |
5282 次 |
| 最近记录: |