How can I check for failure in constructor () without using exceptions?

All the classes I'm working on have Create () / Destroy () (or Initialize () / Finalized ()) methods.

The return value of the Create () bool method , as shown below.

bool MyClass::Create(...);

So, I can check if instance initialization is successful or not from the return value.

Without Create () / Destroy () I can do the same job in constructor () and destructor (), but I can not solve the problem below.

Can anyone help me? Thanks in advance.

I cannot use exceptions because my company does not like this.

class Foo
{
private:
    AnotherClass a;
public:
    Foo()
    {
        if(a.Initialize() == false)
        {
            //???
            //Can I notify the failure to the user of this class without using exception?
        }
    }
    ...
};

Foo obj;
+3
source share
9 answers

, , :

  • / , .
  • , . .

, , , .

+6

; , . :

  • - assert() , ; , .
  • Init.
  • ... , "" .

, 2 , 3, , "check" . , , , , .

+3

, . : bool Initialize(), bool Uninitialize() .

+3

? - . , , , throwing .

FAQ: , ?

+2

, , , init:

class Foo
{
private:
    AnotherClass a;
public:
    Foo(){};
    bool initialize()
    {
        return a.Initialize();
    }
    ...
};

Foo obj;
+2

++ ++, , ++ , . , , , . ( , ). , "" , "" , .

, (, , ) . () , , - hodge-podge , .

Foo Initialize, a.Initialize , .

+2

, (--, setjmp/longjmp), . , , , :

int function1(Error& e, char * arg)
{
    if(e.failure())
        return -1; // a legal, but invalid value

    // ...
}

int function2(Error& e, int arg)
{
    if(e.failure())
        return -1; // a legal, but invalid value

    // ...
}

int function3(Error& e, char * arg)
{
    if(e.failure())
        return -1;

    // if function1 fails:
    //  * function2 will ignore the invalid value returned
    //  * the error will cascade, making function2 "fail" as well
    //  * the error will cascade, making function3 "fail" as well
    return function2(e, function1(e, arg));
}

:

class Base1
{
protected:
    Base1(Error& e)
    {
        if(e.failure())
            return;

        // ...
    }

// ...
};

class Base2
{
protected:
    Base2(Error& e)
    {
        if(e.failure())
            return;

        // ...
    }

// ...
};

class Derived: public Base1, public Base2
{
public:
    Derived(Error& e): Base1(e), Base2(e)
    {
        if(e.failure())
            return;

        ...
    }
};

, . new :

// yes, of course we need to wrap operator new too
void * operator new(Error& e, size_t n)
{
    if(e.failure())
        return NULL;

    void * p = ::operator new(n, std::nothrow_t());

    if(p == NULL)
        /* set e to "out of memory" error */;

    return p;
}

template<class T> T * guard_new(Error& e, T * p)
{
    if(e.failure())
    {
        delete p;
        return NULL;
    }

    return p;
}

:

Derived o = guard_new(e, new(e) Derived(e));

:

  • C ( Error )
  • The Error class can be 100% opaque; using macros to access, declare and transmit it, it can include all kinds of information, including, but not limited to, the source file and line, function name, backtrack of the stack, etc.
  • this refers to rather complex expressions, which makes it almost like an exception in many cases
+2
source

two sentences:

  • old fashioned setjmp / longjmp ()
  • errno global variable
0
source
class Foo
{
private:
    AnotherClass a;
    bool m_bInitFail; //store the status of initialization failure

public:
    Foo(bool bInitFail = false) : m_bInitFail(bInitFail)
    {
        m_bInitFail  = a.Initialize();           
    }

    bool GetInitStatus () { return m_bInitFail ; }
};

int main()
{
  Foo fobj;
  bool bStatus = fobj.GetInitStatus();
  return 0;         
}
0
source

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


All Articles