因此,我们有一个构造函数,可以根据传递给它的参数引发异常,但是如果发生这种情况,我们不知道如何删除该对象。代码的重要部分:
try
{
GameBase *gameptr = GameBase::getGame(argc, argv);
if (gameptr == 0)
{
std::cout << "Correct usage: " << argv[PROGRAM_NAME] << " " << "TicTacToe" << std::endl;
return NO_GAME;
}
else
{
gameptr->play();
}
delete gameptr;
}
catch (error e)
{
if (e == INVALID_DIMENSION)
{
std::cout << "Win condition is larger than the length of the board." << std::endl;
return e;
}
}
catch (...)
{
std::cout << "An exception was caught (probably bad_alloc from new operator)" << std::endl;
return GENERIC_ERROR;
}
在第三行中,GameBase::getGame()
调用派生自其中一个游戏的构造函数,GameBase
并返回指向该游戏的指针,并且这些构造函数可以引发异常。问题是,gameptr
如果发生这种情况,我们如何删除指向的(部分?)对象?如果引发异常,我们将退出的范围,gameptr
因为我们离开了try块并且无法调用delete gameptr
。
要评估异常安全性,您需要在中提供有关对象构造的更多详细信息GameBase::getGame
。
规则是,如果抛出构造函数,则不会创建对象,因此不会调用析构函数。关联的内存分配也被释放(即对象本身的内存)。
问题就变成了,如何开始分配内存?如果带有new GameBase(...)
,则无需取消分配或删除结果指针-运行时将释放内存。
为了清楚起见,已经构造的成员变量将如何处理;除了“父”对象外,它们都被破坏。考虑示例代码;
#include <iostream>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
M m_;
C() { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
auto main() -> int {
try {
C c;
}
catch (exception& e) {
cout << e.what() << endl;
}
}
输出是;
M ctor
C ctor
M dtor
std::exception
如果M m_
要动态分配成员,则在裸指针上使用aunique_ptr
或a shared_ptr
,并允许智能指针为您管理对象;如下;
#include <iostream>
#include <memory>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
unique_ptr<M> m_;
C() : m_(new M()) { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
这里的输出反映了上面的输出。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句