odinthenerd
odinthenerd

Reputation: 5552

Is there any trick to detect if an object is created during execution of another destructor?

This is kind of a follow up on Why can't Alexandrescu use std::uncaught_exception() to implement SCOPE_FAIL in ScopeGuard11?

I would like to detect if someone is creating MyClass in the destructor of another class (or with an active destructor somewhere in the call stack).

class MyClass
{
public:
    MyClass(){
        assert(???what to put here????);
    }
}

void f(){
    MyClass m;    //whether this asserts should be context dependant
}

class OtherClass{
    ~OtherClass(){
        MyClass m; //this should assert
        f();       //this should too;
    }
}

int main()
{
    MyClass m;   //this should not assert
    f();         //this should also not assert
}

One attempt might be:

assert(!std::uncaught_exception());

but that would only work if the destructor is being invoked because of an exception, not if it is invoked because the object went out of scope.

Upvotes: 11

Views: 322

Answers (2)

pal
pal

Reputation: 618

you cannot detect this and you don't want to. it's not your class's business. if someone will call you from noexcept destructor, he will catch exceptions

Upvotes: 1

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145359

You can't detect how your function is called unless you make the callers supply that information.

Also, as I recall Visual C++ never implemented std::uncaught_exception, so that would be ungood (for portable code) even where it was known that no destructor invoked any try block.

However, it's trivial to detect whether a scope is exited due to an exception or not.

Simply put that scope in a try-block; that's what it's for.

For example,

class Transaction
{
private:
    bool failed_;
    Transaction( Transaction const& );  // deleted
    Transaction& operator=( Transaction const& ); // deleted

public:
    void fail() { failed_ = true; }

    void commit() { ... }

    // More functionality, then

    ~Transaction()
    {
        if( failed_ ) { rollback(); }
    }

    Transaction(): failed_( false ) {}
};

void foo()
{
    Transaction transaction;

    try
    {
        // blah blah
    }
    catch( ... )
    {
         transaction.fail();
         throw;
    }
}

Disclaimer: I haven't used that pattern so can't attest to how practical it is.

Upvotes: 0

Related Questions