编码

#include <csetjmp>

template <typename Callable>
void create_checkpoint(std::jmp_buf buf, Callable&& callable)
{
    if (setjmp(buf) != 0)
    {
        callable();
    }
}

#include <iostream>

struct announcer {
    int id;
    announcer(int id):
        id{id}
    {
        std::cout << "created announcer with id " << id << '\n';
    }
    ~announcer() {
        std::cout << "destructing announcer with id " << id << '\n';
    }
};

void oopsie(std::jmp_buf buf, bool shouldJump)
{
    if (shouldJump)
    {
        // std::cout << "performing jump...\n";
        std::longjmp(buf, 1);
    }
}

void test1()
{
    std::jmp_buf buf;
    announcer a1{1};
    create_checkpoint(buf, []() {throw std::exception();});
    oopsie(buf, true);
}

void test2()
{
    std::jmp_buf buf;
    announcer a1{1};
    create_checkpoint(buf, []() {throw std::exception();});
    oopsie(buf, false);


    announcer a2{2};
    create_checkpoint(buf, []() {throw std::exception();});
    oopsie(buf, true);
}

int main()
{
    try
    {
        test1();
    }
    catch (...)
    {}

    try
    {
        test2();
    }
    catch (...)
    {}
}

语境

我必须调用一些通过longjmp报告错误的C库。为了提供强大的异常保证,我想创建一个与std::lock_guard非常相似的函数,例如我只是编写create_checkpoint(buf, handler)并继续调用C库函数,直到分配更多资源为止(如果我理解正确,则不会调用setjmp行下方创建的对象的析构函数)。



为什么在这种情况下会调用未定义的行为,我该如何解决?

我如何发现这是未定义的行为?
std::coutPrinting message to std::longjmp 之前的not printing产生非常不同的结果,即使该行与控制流无关。

我现在了解什么?

我知道std::longjmp本质上是还原寄存器并跳转到setjmp宏保存的指令指针。另外,functions are not optimized away,至少在编译期间,有一条指令调用longjmp

create_checkpoint转换为宏seems to solve the issue。但是我不知道有更好的方法吗?

最佳答案

https://en.cppreference.com/w/cpp/utility/program/longjmp



由于您未遵循此规则,因此您的程序具有未定义的行为

10-08 16:27