1

I need to to a modification in an existing function, having some const input parameters:

int f(const owntype *r1, const owntype *r2)

In order to do this, I would like to call a subfunction, who is using the same type, but without the const keyword:

void subfunction (owntype *src, owntype *dst)

I've already tried this (along with quite some other variants), but it does not work:

int f(const owntype *r1, const owntype *r2) {
  ...
  subfunction((const owntyp*) r1);
  ...
}

How can I get this to compile without needing to change the parmeter description of both functions?

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • Why can you not change the parameters of subfunction? – rubenvb Sep 22 '16 at 09:48
  • Both `f()` and `subfunction()` are widely spread in the rest of the program, and I'd prefer to minimise the impact of my modifications. – Dominique Sep 22 '16 at 09:51
  • 5
    If you have the source of `subfunction()`, and it's true that it doesn't modify its arguments, just make them `const`. There will be no "impact". – unwind Sep 22 '16 at 09:53
  • 1
    It would be good to clarify whether `subfunction` actually modifies the pointed-to objects or not – M.M Sep 22 '16 at 09:55
  • `subfunction()` does not modify the mentioned parameters, but it's widespread in the application, and at every place, a variable, not declared as `const`, is used for it. If I change the signature of `subfunction()`, I'll need to do modifications through the whole program, which I want to avoid. – Dominique Sep 22 '16 at 09:57
  • 3
    You don't need to cast when passing pointer to non-const to function expecting pointer to const. It's implicitly converted. No extra work needed. – user694733 Sep 22 '16 at 09:59
  • Without any typecasting, the source code is not compiling, hence my question. – Dominique Sep 22 '16 at 10:01
  • @M.M I was referring to Dominiques response to unwinds suggestion. – user694733 Sep 22 '16 at 10:05
  • Just add const to the subfunction parameters and go from there. Anything else is at least as much work and suboptimal. – rubenvb Sep 22 '16 at 10:14

5 Answers5

5

The best solution would be to modify subfunction to take pointers to const.

In practice sometimes this is not possible (e.g. would require modifying code that is not allowed to be modified due to organizational practices). In those cases you can write:

subfunction( (owntype *)r1, (owntype *)r2 );

This is correct so long as you are sure that subfunction does not modify the pointed-to objects. If it did try to modify them, then undefined behaviour would be caused at the point of attempted modification.

If you are not sure about what subfunction does, and you want to program defensively, then another option is to take copies of the objects:

owntype c1 = *r1, c2 = *r2;
subfunction( &c1, &c2 );

Note, check that making a copy doesn't break class invariants of owntype.


Some other answers/comments suggested it might be undefined behaviour to cast away const. However it isn't. The relevant quote is C11 6.7.3/6:

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.

Link to question on that topic

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
3

As long as subfunction does not attempt to write to the pointed-to objects *r1 and *r2 it's alright to call it through a cast:

subfunction(owntype*)r1, (owntype*)r2);

The standard(§6.7.3) says:

If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined.

So, reading from it is fine, as long as you don't write to it.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
2

You have stated that subfunction does not change the input. Is this by purpose/design or it is possible that future changes may be lead to modifying the input?

In the first case, defining the input not as const clearly is a bug. Since subfunction seems to be under your control: Fix the interface -> done!

In the second case (the interface's constness was correctly chosen) also: do no remove the const! Future changes to that function may break your code on unexpected places. Instead make a local copy and use the copy as an argument to subfunction.

vlad_tepesch
  • 6,681
  • 1
  • 38
  • 80
1

From the comments:

subfunction() does not modify the mentioned parameters, but it's widespread in the application, and at every place, a variable, not declared as const, is used for it. If I change the signature of subfunction(), I'll need to do modifications through the whole program, which I want to avoid.

Note that it is perfectly fine to supply non-const arguments to a functions that is defined with const parameters. So unless subfunction calls other functions that has non-const parameters then it will work fine if you change the parameters to const.

Note that if you want to introduce const in existing code it is easiest to do it bottom-up. Start with the most basic functions (those that don't call any other functions) and work your way up the call hierarchy. That way you can do it bit by bit. If you start at the top (like in main) the code won't compile again until you have changed it everywhere.

Klas Lindbäck
  • 33,105
  • 5
  • 57
  • 82
-1

(const owntype *)r1 is a no-op since the type of r1 already is const owntype *.

The called function (subfunction()) requires an argument of type owntype *. You can cast r1 to owntype * when pass it to subfunction() as an argument but if subfunction() attempts to modify the value then you are in big trouble.

Think a little about the interfaces of the two functions.

int f(const owntype *r1, const owntype *r2)

says: "Give me the addresses of two owntype objects (r1 and r2) and I promise I won't change the objects (const)."

Then it internally passes r1 and r2 to subfunction(). subfunction() didn't promise anything about the values pointed by its arguments (there is no const there) and it feels free to change them. It then returns and f() breaks its promise without even knowing.

This is not how the things work and this is the reason why casting from const to non-const is undefined behaviour.

axiac
  • 68,258
  • 9
  • 99
  • 134