关于C++构造函数抛出异常
2012-12-10 15:50
447 查看
The code like this is inherently vulnerable to memory leaks(if the constructor failed)?
Yes, if allocating b fails, a will be leaked. That’s why youtypically don’t keep naked pointers.
Justify it.
It easy approves the memory leak from the code.
Here are some interpretations about that.
then this alone won't leak the raw memory allocated for thisBad object, even if the constructor of Bad throws.
When you do
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
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
相关文章推荐
- C++关于构造函数 和 析构函数 能否抛出异常的讨论
- [c/c++]构造函数、析构函数中可不可以抛出异常
- C++ 构造函数抛出异常会引起内存泄漏吗?
- C++ 构造函数抛出异常会引起内存泄漏吗?
- C++不能中断构造函数来拒绝产生对象(在构造和析构中抛出异常)
- C++中构造函数和析构函数可以抛出异常吗?
- 关于构造函数 和 析构函数 能否抛出异常的讨论
- 【effective c++】C++构造函数、析构函数与抛出异常
- C++ - 谨防因构造函数抛出异常而引发的问题
- C++构造函数中抛出的异常
- C++构造函数中抛出异常要注意
- C++中构造函数和析构函数可以抛出异常吗?
- C++之构造函数、析构函数抛出异常的问题
- 关于构造函数 和 析构函数 能否抛出异常的讨论
- 关于C++异常抛出指针问题的探讨
- C++构造函数和析构函数中抛出异常的注意事项
- C++中构造函数和析构函数抛出异常问题
- more-effective-c++ 序列2 异常(第10节,在构造函数中抛出异常导致资源泄露)的测试示例
- C++ 构造函数抛出异常会引起内存泄漏吗?
- C++ 构造函数抛出异常会引起内存泄漏吗?