gpt4 book ai didi

c++ - [[noreturn]] 调用必须返回的函数的错误处理程序,仍然收到警告

转载 作者:行者123 更新时间:2023-12-02 01:14:28 25 4
gpt4 key购买 nike

在下面的代码中,两个错误处理程序都被声明为[[noreturn]],我知道如果必须返回值的函数调用一个抛出异常且从不返回的函数,那么这是明确定义的行为。 p>

如果控制到达函数 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);
}

最佳答案

编译器知道一些你不知道的事情。 [[noreturn]] 不是方法签名的一部分,因此派生类中的重写方法可以自由返回。

// '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() final // FINAL is key
{
throw 1;
}

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

class Derived2 :
public Base
{
public:
void ErrorHandler() override
{
return; // AHA! ErrorHandler returns!
}
};


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

Derived d;
d.f(0);

Derived2 d2;
d2.f(0);
}

这里我创建了一个额外的派生类,并向 Derived 添加了一个方法 f

我收到的唯一警告是:

<source>(17) : warning C4715: 'Base::f': not all control paths return a value

它正确地推断出 Derived::f (Base::f 的拷贝)不存在此问题。

Base::f 中的问题由 Derived2 说明 - 其中,ErrorHandler 已在没有 [ 的情况下被覆盖[noreturn]] 属性。属性不是方法签名的一部分

因此,虚拟 ErrorHandler[[noreturn]] 可以被返回的错误处理程序覆盖。这将导致 f 表现出未定义的行为。

当我在 Derived 中将 ErrorHandler 标记为 final 时,那里的 f 不能 表现出未定义的行为(因为无法使用非 [[noreturn]] 重载来覆盖 ErrorHandler)。因此不会生成警告。

<小时/>

如果您假设没有人会用返回的错误处理程序覆盖 ErrorHandler,您仍然可以抑制此警告。

最干净的方法是这样的:

class Base
{
public:
[[noreturn]] void DoErrorHandling() {
ErrorHandler();
throw 0; // or std::terminate
}
private:
[[noreturn]] virtual void ErrorHandler() { throw 0; }
public:
int f(int x) {
if (x > 0)
return x;
DoErrorHandling();
}
};

现在我们用一个标记为 [[noreturn]] 的非虚拟 DoErrorHandling 方法包装 ErrorHandler ,如果虚拟 ErrorHandler 它调用时不会抛出,而是抛出。

关于c++ - [[noreturn]] 调用必须返回的函数的错误处理程序,仍然收到警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59666328/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com