您的位置:首页 > 编程语言 > C语言/C++

关于C++构造函数抛出异常

2012-12-10 15:50 447 查看
The code like this is inherently vulnerable to memory leaks(if the constructor failed)?

class Foo
{
public:
Foo()
: a(new int), b(new int)
{}
~Foo()
{
delete a;
delete b;
}
private:
int *a;
int *b;
};


Yes, if allocating b fails, a will be leaked. That’s why youtypically don’t keep naked pointers.

Justify it.

#include <iostream>
#include <stdexcept>
#include <memory>

class Bad
{
public:
Bad(): id(++counter) { if (counter == 2) throw std::runtime_error("666\n"); }

~Bad() { std::cout << "Destroyed " << id << "\n"; }
int id;
static int counter;
};

int Bad::counter = 0;
typedef Bad* BadPtr;

class X
{
BadPtr a;
BadPtr b;
public:
X(): a(new Bad), b(new Bad) {}
};

int main()
{
try {
X x;
}catch (std::exception& e){
std::cout << e.what() << '\n';
}
}

It easy approves the memory leak from the code.

$ valgrind --leak-check=full --show-reachable=yes


Here are some interpretations about that.

Bad* b = new Bad;

then this alone won't leak the raw memory allocated for thisBad object, even if the constructor of Bad throws.

When you do

X(): a(new Bad), b(new Bad) {}

then the first object is allocated successfully, and if thesecond throws, it won't leak the memory allocated for that object. When itconcerns a, the first sentence applies: a will essentially go out of scope andthe first Bad object is leaked.

Also we can get that information from C++ standards

An object that is partially constructed or partiallydestroyed will have destructors executed for all of its fully constructedsubobjects, that is, for subobjects for which the constructor has completedexecution and the destructor has not yet begun execution.
Should a constructorfor an element of an automatic array throw an exception, only the constructedelements of that array will be destroyed. If the object or array was allocatedin a new-expression and the new-expression does not contain a new- placement,the
deallocation function (3.7.3.2, 12.5) is called to free the storageoccupied by the object; the deallocation function is chosen as specified in5.3.4. If the object or array was allocated in a new-expression and thenew-expression contains a new-placement, the
storage occupied by the object isdeallocated only if an appropriate placement operator delete is found, asspecified in 5.3.4.

Although this problem may be solved by smart pointer such asshared_ptr. We should avoid doing that. There are some morals can be summarized as follows:

Moral #1: Constructor function-try-blockhandlers have only one purpose -- to translate an exception. (And maybe to dologging or some other side effects.) They are not useful for any other purpose.

Moral #2: Since destructors should never emit anexception, destructor function-try-blocks have no practical use at all. Thereshould never be anything for them to detect, and even if there were somethingto detect because of evil code, the
handler is not very useful for doinganything about it because it cannot suppress the exception.

Moral #3: Always perform unmanaged resourceacquisition in the constructor body, never in initializer lists. In otherwords, either use "resource acquisition is initialization" (therebyavoiding unmanaged resources entirely) or else perform
the resource acquisitionin the constructor body.

Moral #4: Always clean up unmanaged resourceacquisition in local try-block handlers within the constructor or destructorbody, never in constructor or destructor function-try-block handlers.

Moral #5: If a constructor has an exceptionspecification, that exception specification must allow for the union of allpossible exceptions that could be thrown by base and member subobjects.

Moral #6: If a constructor of a member objectcan throw but you can get along without said member, hold it by pointer and use the pointer's nullness to remember whether you've got one or not, as usual. Use the Pimpl idiom to group such "optional"
members so you only have to allocate once.

Refs:

http://cboard.cprogramming.com/cplusplus-programming/119715-exception-safe-constructor-destructor.html

http://www.gotw.ca/gotw/066.htm
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: