0

C++

I want a class to throw an exception before its constructor's body's opening curly brace { by using its own member function to prevent construction. I defined a member function, whose purpose is only to unconditionally throw an exception, with an arbitrarily chosen non-void return type and a dummy data member whose type matches that return type, so that I can trigger the throw by constructing this data member with a call to said member function in the constructor initializer list. This works but isn’t elegant because in a non-toy class, the dummy variable would serve no other purpose but to have an excuse for the member function to run, and the member function’s non-void return type serves no other purpose but to have an excuse for it to be callable by the constructor of the dummy data member of the same type.

This toy compiles but isn’t elegant:

class Toy
{
public:
    Toy() : dummy(preventer()) {}
private:
    int dummy;
    int preventer() {throw -1; return 0;}
};

#include <iostream>

int main()
{
    try
    {
        Toy t;
    }
    catch (const int& e)
    {
        std::cout << "caught the exception\n";
    }
    return 0;
}

Console Output:

caught the exception

Without the dummy variable, is there a way to throw an exception before the opening curly brace { of the constructor body?

CodeBricks
  • 1,771
  • 3
  • 17
  • 37
  • 1
    see this thread: http://stackoverflow.com/questions/2672398/throw-exception-from-constructor-initializer? – taocp Mar 28 '13 at 02:23
  • @Ken White, I am not trying to create a singleton in particular. I just want to know how to prevent construction before the constructor's body, in general. – CodeBricks Mar 28 '13 at 02:25
  • Got it. :-) I saw the link that @SongWang posted and deleted my comment; must have happened just as you replied. – Ken White Mar 28 '13 at 02:26

2 Answers2

2

Yes you can use a base class instead of a data member, and then invoking the base class' constructor.

Note that old versions of the GNU debugger gdb (some years ago) was unable to break on such exception.

However, works OK with Visual C++, and I believe also with modern versions of the GNU toolchain.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • +1, good answer, and thanks. Gave an up-vote, but I have to choose an answer to accept, and the accepted answer gives an additional solution in addition to the inheritance one. – CodeBricks Mar 29 '13 at 23:42
1

You can avoid the dummy return value of the function like this:

bool called = (function(), true);

The comma-operator in between the two expressions on the right evaluates the expressions in turn, discarding all but the last's result. What I'm wondering though is why you insist on doing that before the opening curly braces. What exactly are you trying to achieve here that you can't achieve with a call to the function as first thing in the body?

Note that if you want to abort as early as possible, doing that in a separate baseclass (you can use private inheritance there) is probably the best solution. It's the only solution that allows you to prevent even the construction of other bases, which your solution doesn't.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
  • To answer your question: I am trying to prevent construction as soon as possible instead of in the ctor body for performance reasons. I want to prevent construction in certain runtime-determined use cases. In these cases, I want to prevent construction before the expensive data members are constructed in turn. – CodeBricks Mar 29 '13 at 16:00
  • In that case, the constructor of the first baseclass would be a good place. However, I'm not convinced that your very approach is ound. Allocating memory and handling an exception is an expensive operation, so I'd rather avoid that in the first place. That's your decision though. Good Luck! – Ulrich Eckhardt Mar 29 '13 at 17:41
  • I presume your `bool called = (function(), true);` comma operator approach is part of an in-class-definition data member initializer. Is there any way to do that in the ctor initializer? – CodeBricks Mar 29 '13 at 18:45
  • Yes, of course, you can do that in the initializer list: "...m_called((function(), true))". Note that there's no reason for this if you move the whole stuff to a baseclass. – Ulrich Eckhardt Mar 29 '13 at 21:03