C ++ exception security

Exceptional C ++ mentions the following code

template <class T> class Stack { public: Stack(); ~Stack(); /*...*/ private: T* v_; // ptr to a memory area big size_t vsize_; // enough for 'vsize_' T's size_t vused_; // # of T actually in use }; template<class T> Stack<T>::Stack() : v_(new T[10]), // default allocation vsize_(10), vused_(0) // nothing used yet { } 

It says that if one of the constructors of T dropped, then all the objects of T that were completely built were properly destroyed and, finally, the delete operator was automatically called to free memory. It makes us airtight.

I realized that if the constructor throws an exception, the application should clear any allocated resources. What is the higher leak?

+6
source share
3 answers

Citation of the C ++ 03 standard, §5.3.4 / 8:

The new expression gets storage for the object by calling the distribution function. If a new expression completes by throwing an exception, it can free memory by calling the free function. If the assigned type is a non-array type, the name of the distribution function is operator new , and the name of the delete function is operator delete . If the selected type is an array type, the name of the distribution function is operator new[] , and the name of the function is the function operator delete[] .

§5.3.4 / 17:

If any part of the object initialization described above ends with the exception being thrown and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object is built, after which the exception continues to propagate in the context of the new expression.

Therefore, if any T constructor throws an exception, the runtime will destroy any already created subobjects of the T instance created by the constructor, then it will call operator delete[] in the array as a whole, created elements and free the memory of the array.

+8
source

[Correction:] This is not so. An exception in your constructor will not be a resource leak, because the only place where an exception can occur is inside the new expression, and if a new expression is not executed, the resources that were allocated to it are freed. Your situation is special, because you only make one selection in the constructor - in general this is unsafe!

Your quoted phrase refers to the delete operator for a failed object whose constructor threw:

 struct T { T() { throw 1; } char data[200]; }; // in your code: T * pt = new T; 

On the last line, memory is allocated before the constructor is called. This memory is freed in the event of an exception by automatically calling ::operator delete(pt) . (In general, the corresponding delete operator is called (not the "expression"!), Which corresponds to the new expression.)

This happens as follows:

  • Successful design: 1. Distribution. 2. Construction. 3. Destruction. 4. Release.

  • Bad design: 1. Isolation. 2. Release.

Please note: we only have an object after the constructor completes, therefore, in case of an exception, we do not even have an object in the constructor. This is why I said “unsuccessful object” above with a hyphen because it is not an object at all (for example, Douglas Fir is not fir at all).

Your code potentially runs completely unsafe if you make more than one distribution that can be thrown, that is, a leak occurs whenever one object was successfully constructed and another, the next one is not executed. You probably just can't call new in the initializer list and instead put it in the body:

 class Danger { T * pt1, * pt2; public: Danger() { try { pt1 = new T; } catch(...) { throw(); } try { pt2 = new T; } catch(...) { delete pt1; throw(); } } }; 

Or, on a sole responsibility basis, do not use raw pointers, but use resource management containers that are cleared after themselves !!

+3
source

Try auto search for T* v_ or any dynamic dedicated resources. If the following happens

 template<class T> Stack<T>::Stack() : v_(new T[10]), vsize_(10), vused_(0) { throw 0; // terminated by exception } 

or there is another object in the Stack throw exception during construction, v_ will cause a memory leak. If you wrap it as std::unique_ptr<T[]> v_ or something like this, it will be automatically released if the Stack construct is completed with an exception.

0
source

Source: https://habr.com/ru/post/894338/


All Articles