C ++ Class Keys

I have the following C ++ code

template <class E> class ExceptionWrapper { public: explicit ExceptionWrapper(const E& e): e(e) {} void throwException() { throw e; } private: E e; }; ... try { ExceptionWrapper<E> w(...); w.throwException(); } catch (const E& e) { ... } ... 

Question: Is this code valid? I could argue that returning a reference to a class member is almost always invalid (and I'm sure everyone agrees with this statement). However, my colleague claims that this does not apply to throw .

PS after changing catch (const E& e) to catch (E e) unpleasant error seemed to disappear, which strengthened my position - this code is invalid.

+8
c ++ reference exception
Oct. 20 '15 at 16:30
source share
3 answers

I claim that catching e by reference is not valid, since e is a member of w and w is not alive in the catch scope.

Your claim is incorrect. throw e; produces a copy of the element, and this copy is valid in the catch area.

ยง 15.1 / 3 (draft n3797):

Throwing copies of exceptions - initializes (8.5, 12.8) a temporary object , called an exception object, temporary - this is the value of lvalue and is used to initialize the variable specified in the corresponding handler (15.3). If the type of the object of the exception is an incomplete type or a pointer to an incomplete type, the program that is different from (possibly taking into account the qualifications) is invalid is poorly formed. Evaluation face-off expression with throw operand exception; the type of exception object is determined by removing any top-level CV classifiers from the static type of the operand and setting the type from the "array T" or "returning the function T" to "pointer to T" or "pointer to the return function T, respectively.

Catching const is the preferred way to throw exceptions. It allows you to catch derivatives of std::exception without slicing the exception object.

+7
Oct 20 '15 at 16:54
source share
โ€” -

I think the appropriate moment:

15.1. Throwing an exception:

p3. The expression expression initializes a temporary object called an exception object whose type is determined by removing any top-level cv qualifiers from the static type of the throw operand and setting the type from the "array T" or "function returning T" to "pointer to T" or "pointer to the return function T", respectively. Temporary is the value of lvalue and is used to initialize the variable specified in the corresponding handler (15.3). If the type of the exception object is an incomplete type or a pointer to an incomplete type other than the (possibly cv-qualified) void program is poorly formed. With the exception of these restrictions and restrictions in the type matching mentioned in 15.3, the throw operand is treated exactly as a function argument to the call (5.2.2) or the operand of the return statement.

This is from a draft for C ++ 11 , my emphasis.

This basically means that there is a temporary object created from the throw argument. Just like the E f(){return private_e;} function was, and this temporary value is used as an argument to the corresponding handler. That way, you would have two possible copies if you didnโ€™t catch the link.

Probably also relevant:

p5. When the thrown object is an object of the class, the copy / move constructor and destructor must be accessible, even if the copy / move operation is completed (12.8).

+2
Oct 20 '15 at 17:08
source share

If the constructor does not work / throws, w does not exist. So "w.throwException ()" is not valid.

-four
Oct 20 '15 at 16:39
source share



All Articles