与对象展开顺序有关的嵌套try-catch块的行为是什么?

问题描述 投票:0回答:2

因此,我正在尝试C ++展开,并遇到了这种奇怪的行为:在其中,我们有一个嵌套的try-catch块,而在外部,我们构造了一个对象。似乎在内部try-catch处理程序之一中捕获异常时破坏了该对象。

此外,如果我们如本例所示使用动态内存分配(我们在构造函数中使用new,在析构函数中使用delete,则该程序似乎在运行时产生诊断消息。

考虑此代码:

#include <stdio.h>

struct test {
    test(int);
    ~test() throw(int);
    int *b;
};

void f5() {
    if (!printf(""))
        throw 9;
}

test f(int, test) throw(int) { test tmp(6); f5();  return tmp; }

test::test(int a) : b(new int(a)) { printf("constructor test@%d\n", *b); }

test::~test() throw(int)
{
    printf("destructor test@%d\n", *b);
    delete b;
}

int main() {
    test tmp(0);
    try {
        test tmp(1);
        try {
            f(7, tmp);
        }
        catch (int) {
            printf("catch(int)@%d\n", 2);
            try {
                test tmphandler(3); f(7, tmp);
            }
            catch (int) {
                printf("catch(int)@%d\n", 4);
            }
        }

        printf("b = %d\n", *tmp.b);

        f(7, tmp);
    }
    catch (int) { printf("catch(int)@%d\n", 5); }
}

这里是该程序的wandbox输出:

*** Error in `./prog.exe': double free or corruption (fasttop): 0x00000000020ee180 ***
....back-trace of addresses
constructor test@0
constructor test@1
constructor test@6
destructor test@6
destructor test@1
catch(int)@2
constructor test@3
constructor test@6
destructor test@6
destructor test@3
destructor test@33722768

我正在努力理解为什么在catch @ 2时,外部try范围内的对象被破坏了(即,在1上创建的对象)。

c++ try-catch
2个回答
0
投票

不确定标准,但是最近我正在阅读Deitel的有关C ++的书,下面是其中的一段:

17.4堆栈展开

当引发异常但未在特定范围内捕获异常时,函数调用堆栈将“展开”,并尝试在下一个外部try ... catch块中捕获异常。展开函数调用堆栈意味着未捕获异常的函数终止,该函数中已完成初始化的所有局部变量均被销毁,控制权返回到最初调用该函数的语句。如果try语句包含该语句,则会尝试捕获该异常。如果try块未包含该语句,则将再次发生堆栈展开。如果没有捕获处理程序捕获到此异常,则程序终止。

我希望这能回答您的问题。


0
投票

首先,我缺少一个复制构造函数,因此在运行时缺少了诊断消息。第二-析构函数实际上是为从f复制而来的tmp参数调用的,因此1的值会在销毁该对象时销毁,该对象在捕获异常时已正确销毁。这是不混淆的固定变体:

#include <stdio.h>

struct test {
    test(const test&);
    test(int);
    ~test() throw(int);
    int *b;
};

void f5() {
    if (!printf(""))
        throw 9;
}

test f(int, test) throw(int) { test tmp(6); f5();  return tmp; }

test::test(int a) : b(new int(a)) { printf("constructor test@%d\n", *b); }

test::test(const test& a) : b(new int(7)) {}

test::~test() throw(int)
{
    printf("destructor test@%d\n", *b);
    delete b;
}

int main() {
    test tmp(0);
    try {
        test tmp(1);
        try {
            f(7, tmp);
        }
        catch (int) {
            printf("catch(int)@%d\n", 2);
            try {
                test tmphandler(3); f(7, tmp);
            }
            catch (int) {
                printf("catch(int)@%d\n", 4);
            }
        }

        printf("b = %d\n", *tmp.b);

        f(7, tmp);
    }
    catch (int) { printf("catch(int)@%d\n", 5); }
}

输出为:

constructor test@0
constructor test@1
constructor test@6
destructor test@6
destructor test@7
catch(int)@2
constructor test@3
constructor test@6
destructor test@6
destructor test@7
destructor test@3
catch(int)@4
b = 1
constructor test@6
destructor test@6
destructor test@7
destructor test@1
catch(int)@5
destructor test@0
© www.soinside.com 2019 - 2024. All rights reserved.