Используется ли static_cast неправильно? - PullRequest
14 голосов
/ 10 февраля 2011

Я испытываю смешанные чувства по поводу 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 в некоторых случаях, или я что-то упускаю?

РЕДАКТИРОВАТЬ: я знаю, что требуется преобразование в COM , но это не обязательно должно быть static_cast, неявного приведения будет достаточно.

1 Ответ

5 голосов
/ 10 февраля 2011

В этом конкретном случае я считаю, что всегда известно, что литье будет вверх и, следовательно, static_cast должно быть совершенно безопасно.

Похоже, что использование вашего implicit_cast будет, вероятно, безопаснее,и позволяет вам явно выбирать, к какому базовому классу вы хотите неявно приводить (что, очевидно, требуется для COM).

Я провел быстрый тест с g ++, и implicit_cast действительно возвращает разные адреса для разных базовых классов.как и ожидалось.

Заметьте, однако, что в отношении вашего самого первого предложения я бы сказал, что dynamic_cast на самом деле безопаснее, чем static_cast, поскольку он вернет ноль или бросок, если приведение не может быть завершено.,Напротив, 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;
}
...