Есть ли какой-либо трюк, чтобы определить, создан ли объект во время выполнения другого деструктора?

Это будет следствием Почему Alexandrescu не использует std:: uncaught_exception() для реализации SCOPE_FAIL в ScopeGuard11?

Я хотел бы определить, создает ли кто-то MyClass в деструкторе другого класса (или с активным деструктором где-то в стеке вызовов).

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
}

Одна попытка может быть:

assert(!std::uncaught_exception());

но это будет работать только в том случае, если деструктор вызывается из-за исключения, а не если он вызывается, потому что объект вышел из области видимости.

Ответ 1

вы не можете обнаружить это, и вы этого не хотите. это не ваш классовый бизнес. если кто-то вызовет вас из-за отсутствия деструктора, он поймает исключения

Ответ 2

Вы не можете определить, как вызывается ваша функция, если вы не предоставите эту информацию своим абонентам.

Также, как я помню, Visual С++ никогда не реализовывал std::uncaught_exception, поэтому это было бы непригодным (для переносимого кода) даже там, где было известно, что ни один деструктор не вызвал какой-либо блок try.

Однако, тривиально, чтобы определить, выходит ли область из-за исключения или нет.

Просто поставьте эту область в try -block; что за это.

Например,

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;
    }
}

Отказ от ответственности: я не использовал этот шаблон, поэтому не могу подтвердить, насколько он практичен.