shane
shane

Reputation: 1863

Assign const char * member of const argument to new value

I am dealing with a third party library where I would like to modify a structure for the sake of simplicity in my code.

There is a third party struct

struct structure {
    const char *c;
    // ...
};

I have a function

void prep(const structure *s) {
    std::string str("hello");
    const char *t_c = s->c;
    s->c = str.c_str(); // structure::c is a const char *
    handle(s); // makes use of overriden c
    s->c = t_c; // Set back in case library tries to free/use memory later
}

How do I do the appropriate const casting here?

Upvotes: 0

Views: 299

Answers (1)

François Andrieux
François Andrieux

Reputation: 29022

I'm assuming handle is declared as void handle(const structure*);.

The easiest solution is to copy s, modify the copy and then pass it to handle. Since s is const you know that there are no changes that could be made to the copy that would need to be propagated to the original s. You also eliminate the need to reset s->c to it's original value.

void prep(const structure *s) 
{
    structure mycopy(*s); // Make a copy of s
    std::string str("hello");
    mycopy.c = str.c_str(); // structure::c is a const char *
    handle(&mycopy); // makes use of overriden c
}

If you can't copy structure, consider modifying your function declaration by removing the const specifier for s. If you simply remove const you get the following function which compiles fine. Note that the resulting function is not exception safe. If handle throws an exception, you will fail to reset the s->c member to it's original value.

void prep(structure *s)
{
    std::string str("hello");
    const char *t_c = s->c;
    s->c = str.c_str(); // structure::c is a const char *
    handle(s); // makes use of overriden c
    s->c = t_c; // Set back in case library tries to free/use memory later
}

If all else fails you might be able to use const_cast as a last resort. Be sure that s doesn't point to an instance that is actually const and be sure that no exception is thrown while s is not in it's original state. Being forced to use of const_cast may be an indicator of bad design decisions.

void prep(const structure *s) 
{
    std::string str("hello");
    const char *t_c = s->c;
    const_cast<structure*>(s)->c = str.c_str(); // structure::c is a const char *
    handle(s); // makes use of overriden c
    const_cast<structure*>(s)->c = t_c; // Set back in case library tries to free/use memory later
}

Upvotes: 2

Related Questions