Warning C26474

Don't cast between pointer types when the conversion could be implicit.

C++ Core Guidelines:
Type.1: Avoid casts

In some cases, implicit casts between pointer types are safe and don't require you to write a specific cast expression. This rule finds instances of unnecessary casts you can safely remove.

Remarks

The rule ID should be interpreted as "An implicit cast isn't used where it's acceptable."

This rule is only applicable to pointers. It checks static casts and reinterpret casts.

These cases are acceptable pointer conversions that shouldn't use explicit cast expressions:

  • conversion to nullptr_t;
  • conversion to void*;
  • conversion from a derived type to its base when invoking a base member function that's not hidden by the derived type.

Example 1

An unnecessary conversion hides a logic error in this example:

template<class T>
bool register_buffer(T buffer) {
    auto p = reinterpret_cast<void*>(buffer); // C26474, also 26490 NO_REINTERPRET_CAST
    // To fix, declare buffer as T*, and use this to define p:
    // auto p = buffer;
    return buffers_.insert(p).second;
}

void merge_bytes(std::uint8_t *left, std::uint8_t *right)
{
    if (left && register_buffer(*left)) { // Unintended dereference!
        // ...
        if (right && register_buffer(right)) {
            // ...
        }
    }
}

Example 2

This example demonstrates using casts to access base-class member functions:

struct struct_1
{
    void foo();
    void bar();
};

struct struct_2 : struct_1
{
    void foo(); // this definition hides struct_1::foo
};

void fn(struct_2* ps2)
{
    static_cast<struct_1*>(ps2)->foo(); // This cast is necessary to access struct_1::foo
                                        // Alternatively, use ps2->struct_1::foo();
    static_cast<struct_1*>(ps2)->bar(); // This cast is unnecessary and can be done implicitly
}