11

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.

Community
  • 1
  • 1
odinthenerd
  • 5,422
  • 1
  • 32
  • 61
  • 7
    Unless you design those destructors explicitly to signal their execution anyhow, I doubt this is possible. In general, you can't tell where your function has been called from. – Andy Prowl Feb 18 '13 at 15:39
  • How portable do you want the solution to be? – Flexo Feb 18 '13 at 15:39
  • You can specialize your solution to a specific compiler version, and examine the stack in the constructor of `MyClass`, to find the destructor of `OtherClass`. I personnally think it is way too much work for what it is... and will be an error source. – Synxis Feb 18 '13 at 16:37
  • I feared there would not be a good answer, but then again I am always amazed at how many intricate tricks people come up with in meta programming. Who knows maybe Alexandrescu 2.0 will come along and baffle us all. – odinthenerd Feb 18 '13 at 17:04
  • Not even per compiler – per compiler _and_ optimization level _and_ other compiler flags. I think it's unfeasible to do outside lab conditions, except as @AndyProwl suggested. – Jonas Schäfer Feb 18 '13 at 19:02
  • You might be interested in [uncaught_exception_count](http://liveworkspace.org/code/49MaPk%240). – Mankarse Feb 18 '13 at 20:00
  • With GCC, something like `assert(__builtin_return_address(1) != &~OtherClass::OtherClass())` could work. Now you only need to figure how to templatize that for _any_ class name. – Damon Feb 18 '13 at 22:17
  • @Damon: templates won't help, templates make copies of code, but only one at a time is used. – Mooing Duck Feb 20 '13 at 00:12

2 Answers2

1

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

pal
  • 618
  • 4
  • 9
0

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.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331