我有Java经验,最近正在做一些C++编码.我的问题是,如果我有A类,我必须将B类和C类实例化为A的两个成员变量.
如果在A的构造函数中,我是否应该假设B类和C类的分配永远不会失败,并在A的析构函数中处理错误的分配异常?
如果我没有做出这个假设,意味着我添加了一些try catch块来捕获类B和类C的bad_alloc,那么如果发生分配异常,我应该在A的构造函数中进行清理吗?
推荐的做法是什么?如果"new"生成错误分配,指针会携带什么值?
如果在构造A期间抛出异常,则不会调用析构函数.
显然,解决方案取决于你在做什么,但最好你不会有做任何清理.你应该使用RAII,你的班级成员应该自己清理.
也就是说,不要使用任何指针原始; 将它们包起来让包装物处理它.惊喜!C++程序员就像你一样讨厌内存管理.我们喜欢把它包起来忘记它.
但是,如果你真的需要,我认为这很常见:
struct foo
{
int* i;
some_member_that_could_throw crap;
foo() // do *not* new i! if the second member throws, memory is leaked.
{ // rather:
// okay we made it, the other member must have initialized
i = new int;
}
};
Run Code Online (Sandbox Code Playgroud)
关于你的指针,它的值保持不变.当new抛出异常(无论出于何种原因)时,堆栈被解开.表达的其余部分被放弃了.
以下是异常和对象创建的工作原理.这是一个递归过程,因为每个成员或基类将依次遵循此列表.基本类型没有构造函数; 这是递归的基本情况.
显然,如果第1项失败,我们没有任何清理工作,因为我们的成员都没有被初始化.我们在那里很好.
两个是不同的.如果其中任何一个都无法构造,那么到目前为止的初始化成员将被破坏,然后构造函数将停止进度,异常继续进行它的快乐方式.这就是为什么当你让自己的成员自己清理干净时,你无需担心.未初始化无关,并且初始化将使其析构函数运行,其中清理发生.
三甚至更是如此.既然您的对象已完全初始化,那么您可以保证它们都会运行析构函数.再次,包装起来,你没有什么可担心的.但是,如果你有一个原始指针,这是try/catch块的时间:
try
{
// some code
}
catch (..) // catch whatever
{
delete myrawPointer; // stop the leak!
throw; // and let the exception continue
}
Run Code Online (Sandbox Code Playgroud)
在没有RAII的情况下编写异常安全的代码要麻烦得多.
| 归档时间: |
|
| 查看次数: |
3353 次 |
| 最近记录: |