首页 > 解决方案 > [[noreturn]] 错误处理程序调用必须返回的函数,仍然收到警告

问题描述

在下面的代码中,两个错误处理程序都声明为[[noreturn]],我知道必须返回值的函数调用抛出且永不返回的函数是否是明确定义的行为。

如果控制在f没有 return 语句的情况下到达函数末尾,那将是未定义的行为,但这是不同的,因为 return 永远不会发生。

// 'function' must return a value
#pragma warning(default:4716)

class Base
{
public:
    [[noreturn]] virtual void ErrorHandler()
    {
        throw 0;
    }

    int f(int x)
    {
        if (x > 0)
            return x;
        else ErrorHandler();    // C4716
    }
};

class Derived :
    public Base
{
public:
    [[noreturn]] void ErrorHandler() override
    {
        throw 1;
    }
};

int main()
{
    Base b;
    b.f(0);

    Derived d;
    d.f(0);
}

这仍然是UB,如果不是,那么为什么我会收到警告?

除了上述问题,我想要一个ErrorHandler可以处理异常并将控制权返回给调用者的设计,在这种情况下,我如何知道被覆盖的处理程序是否返回?

例如,我们可以删除[[noreturn]]并假设处理程序可能返回也可能不返回,那么如何设计函数f?如果参数为零但返回值必须非零,则返回什么?

主要我想摆脱警告并确保行为已明确定义,并且返回值必须为正值,否则函数f将无法继续。

编辑

如果我们将代码修改为具有非虚拟错误处理程序,则警告消失。

那么是什么让第一个案例引发了警告呢?有什么不同?

   class Base
    {
    public:
        [[noreturn]] void ErrorHandler()
        {
            throw 0;
        }

        int f(int x)
        {
            if (x > 0)
                return x;
            else ErrorHandler();    // OK
        }
    };

    class Derived :
        public Base
    {
    public:
        [[noreturn]] void ErrorHandler()
        {
            throw 1;
        }
    };

    int main()
    {
        Base b;
        b.f(0);

        Derived d;
        d.f(0);
    }

标签: c++error-handling

解决方案


[[noreturn]] virtual void ErrorHandler()只告诉该函数不会返回。

我不强制继承的类“继承”属性。

如果你想强制异常,你可能会返回std::exception_ptr

class Base
{
public:
    [[noreturn]] virtual std::exception_ptr ErrorHandler()
    {
        std::make_exception_ptr(0);
    }

    int f(int x)
    {
        if (x > 0) {
            return x;
        } else {
            auto eptr = ErrorHandler();
            if (eptr) {
                rethrow_exception(eptr);
            }
            throw "nullptr eptr";
        }
    }
};

class Derived :
    public Base
{
public:
    [[noreturn]] std::exception_ptr ErrorHandler() override
    {
        std::make_exception_ptr(1);
        // or even
        // throw 1;
    }
};

推荐阅读