static_cast 被滥用了吗?

发布于 2024-10-16 23:06:16 字数 1065 浏览 2 评论 0原文

我对 static_cast 的感受很复杂,因为它是可用的最安全的 C++ 转换,但同时允许安全和不安全的转换,因此您必须了解上下文才能判断它是否实际上安全或可能会导致 UB(例如,当转换为子类时)。

那么为什么没有更安全的显式强制转换呢?这是一个示例,它可能很有用。在 COM 中,它们必须将接口指针返回为 void** ppv,因此“必须”显式强制转换

*ppv = (IInterface*) this;

,然后建议将其替换为更安全的 C++ 强制转换

*ppv = static_cast<IInterface*>(this);

但这是否有意义这里有一个static_cast吗? this 属于从 IInterface 派生的类,因此可以简单地编写

IInterface* p = this; // implicit conversion to base, safe for sure
*ppv = p;

或使用像这样的帮助器

template<class T, class U>
T implicit_cast(U p) { return p; }

*ppv = implicit_cast<IInterface*>(this);

那么,static_cast 有时是真的吗?在某些情况下被误用并且可以(应该?)被这个 implicit_cast 取代,还是我遗漏了一些东西?

编辑:我知道 a COM 中需要强制转换,但不一定是 static_cast,隐式强制转换就足够了。

I have mixed feelings about static_cast, as it is the safest C++ cast available, but allows both safe and unsafe conversions at the same time, so you have to know the context to say if it is actually safe or might lead to UB (e.g. when casting to a sub-class).

So why isn't there a safer explicit cast? Here is an example, where it could be useful. In COM, they have to return the interface pointer as void** ppv, so "have to" cast explicitely

*ppv = (IInterface*) this;

which was then suggested to be replaced by a safer C++ cast

*ppv = static_cast<IInterface*>(this);

But does it make sense to make even a static_cast here? this is of a class which derives from IInterface, so one could simply write

IInterface* p = this; // implicit conversion to base, safe for sure
*ppv = p;

or use a helper like

template<class T, class U>
T implicit_cast(U p) { return p; }

*ppv = implicit_cast<IInterface*>(this);

So, is it true that static_cast is sometimes misused and can (should?) be replaced by this implicit_cast in some cases, or am I missing something?

EDIT: I know that a cast is required in COM, but it does not have to be static_cast, an implicit cast would be enough.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花之痕靓丽 2024-10-23 23:06:16

在这种特殊情况下,我相信总是知道强制转换将向上,因此 static_cast 应该是完全安全的。

使用 implicit_cast 似乎确实会更安全,并且允许您显式选择要隐式转换到的基类(这显然是 COM 所必需的)。

我用 g++ 做了一个快速测试,implicit_cast 确实按预期为不同的基类返回了不同的地址。

但请注意,关于您的第一句话,我认为 dynamic_cast 实际上比 static_cast 更安全,因为如果无法进行强制转换,它将返回 null 或抛出异常。完全的。相反,static_cast 将返回一个看起来有效的指针,并让您继续运行,直到您的程序在未来某个时间崩溃,与原始的错误强制转换无关。

测试程序:

#include <iostream>

class B1
{
public:
    virtual ~B1() {}
};

class B2
{
public:
    virtual ~B2() {}
};

class Foo : public B1, public B2
{
};

template<class T, class U>
T implicit_cast(U p) { return p; }

int main()
{
    Foo* f = new Foo;
    void **ppv = new void*;

    *ppv = implicit_cast<B1*>(f);
    std::cout << *ppv << std::endl;;
    *ppv = implicit_cast<B2*>(f);
    std::cout << *ppv << std::endl;;

    return 0;
}

In this particular case I believe that it's always known that the casting will be upwards and that therefore static_cast should be perfectly safe.

It does appear that using your implicit_cast would probably be safer, and allows you to explicitly pick which base class you want to implicitly cast to (which is apparently required for COM).

I did a quick test with g++ and implicit_cast does indeed return different addresses for different base classes as expected.

Do note however that in regards to your very first sentence I would argue that dynamic_cast is in fact safer than static_cast since it will return null or throw if the cast can't be completed. In contrast, static_cast will return a valid-looking pointer and let you keep going until your program blows up at some time in the future, unconnected to the original bad cast.

Test program:

#include <iostream>

class B1
{
public:
    virtual ~B1() {}
};

class B2
{
public:
    virtual ~B2() {}
};

class Foo : public B1, public B2
{
};

template<class T, class U>
T implicit_cast(U p) { return p; }

int main()
{
    Foo* f = new Foo;
    void **ppv = new void*;

    *ppv = implicit_cast<B1*>(f);
    std::cout << *ppv << std::endl;;
    *ppv = implicit_cast<B2*>(f);
    std::cout << *ppv << std::endl;;

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文