Search code examples
c++castingconst-cast

const_cast with two levels pointers


I want to do this conversion using C++ format, it works on the C way. but it fails when I try on C++ format.

It works!

void req_password(const void *data, size_t datalen)
{
    char *password_old = ((char **) data)[0];
    char *password_new = ((char **) data)[1];
    ...
}

It fails

void req_password(const void *data, size_t datalen)
{
    char *password_old = (const_cast<char **>(data))[0];
    char *password_old = (const_cast<char **>(data))[1];
    ...
}

error:

error: invalid const_cast from type 'const void*' to type 'char**'

So my doubt is, how could I do this conversion using the C++ way?

PS: This code is part from a API, I can't control the the input of data.


Solution

  • Don't.

    If you are being given immutable data, then you are being given immutable data and that is the end of it!

    First, here's what I suggest for maximum safety. Coercing data into its real type is a little tricky, alas:

    void req_password(const void* data, size_t datalen)
    {
        const char* password_old = (reinterpret_cast<const char* const*>(data)[0]);
        const char* password_new = (reinterpret_cast<const char* const*>(data)[1]);
        // ...
    }
    

    (I've actually added some constness in the above, as it seems to be the intent of having const void* in the first place.)

    But, if you really want the strings to be mutable, then this is fine too:

    void req_password(const void* data, size_t datalen)
    {
        char* password_old = (reinterpret_cast<char* const*>(data)[0]);
        char* password_new = (reinterpret_cast<char* const*>(data)[1]);
        // ...
        // More obvious when you recall that `const void*` is actually `void const*`;
        // So:
        //   void  const*
        // becomes:
        //   char* const*
    }
    

    Notice how you don't even need const_cast here, because you're not modifying the thing that data points to: you are dereferencing it and getting its pointee.

    Of course, ideally, data would point to a const std::string instance.