Sign in to follow this  
b34r

const clarifications wanted...

Recommended Posts

Hi, Correct me if I'm wrong please: - void class::Dummy(const Object *o) {...} Nice from an API design point of view, explicitly declares that the object won't be modified. Some place for optimisation. - void class::Dummy(const Object * const o) {...} More place for optimisation since o is guaranteed not to change (?). Is it worth the trouble to go from 'const *' to 'const * const' where possible and... - GCC does not require the const * const form to be declared both in the header and implementation, what about other compilers? Thanks!

Share this post


Link to post
Share on other sites
Quote:
- void class::Dummy(const Object *o) {...}
Nice from an API design point of view

Correct, but forget the optimization part. Unless you use the -no-aliasing compiler flag you'll probably not see any optimization based on the const.
This is a subject that can be discussed in length. But the basic problem is that the compiler cannot be sure that the const reference is _the only_ reference to that object. You could have another non-const-reference somewhere that modifies the object. And hence, the compiler cannot cache the object's values even when it's const. With the -no-aliasing flag the compiler assumes that no memory is accessed through more than one reference. This is a very dangerous assumption, so it's not wise to use the flag. =)

Quote:
- void class::Dummy(const Object * const o) {...}

This is a completley different type. Now the pointer itself is const, not only the object it points too. This is usually not what you want.

[edit]To conclude: It's not worth the trouble to use 'const * const' even when possible. And if you need the code to be optimized don't rely on the compiler[/edit]

Share this post


Link to post
Share on other sites
Quote:
Original post by greldik
This is a completley different type. Now the pointer itself is const, not only the object it points too. This is usually not what you want.

Indeed, it would be like passing in "const int" - pretty pointless.

Share this post


Link to post
Share on other sites
Quote:
Original post by Andrew Russell
Quote:
Original post by greldik
This is a completley different type. Now the pointer itself is const, not only the object it points too. This is usually not what you want.

Indeed, it would be like passing in "const int" - pretty pointless.


But in theory at least, a "const int" can be optimized, because it is guarenteed not to be changed, and the same goes for a pointer. Whether or not it works in practice, I don't know.

Share this post


Link to post
Share on other sites
Oh and, pure curiosity but, do you have an example of where the 'const * const' form might be better?

Share this post


Link to post
Share on other sites
Quote:
Original post by swiftcoder
But in theory at least, a "const int" can be optimized, because it is guarenteed not to be changed

No.

A non-const int is guarenteed not to change, because it's passed by value (a copy is made). Making it const dosn't provide any extra guarentees to the caller. It only places a limitation on the implementation of the function.

Which is the reason that the implementation can remove the const as b34r said in his first post. It is because the compiled code is exactly the same.

Share this post


Link to post
Share on other sites
Quote:
Original post by b34r
Oh and, pure curiosity but, do you have an example of where the 'const * const' form might be better?

A reference or pointer to a const pointer to a const object.

The actual value passed to the function is always passed in by value (pretend references are pointers here - they basically are in compiled code anyway). This means making the "head" of a type of an argument const is pointless.

In other words, when passing in a pointer to an object, the pointer itself is passed in by value - that is - a copy is made. Because of this - it dosn't matter if it's const or not - the caller knows it can't be changed.

Share this post


Link to post
Share on other sites
First, const is more or less just a mean to clarify your code, no optimizations can be concluded from using const.

Quote:
It only places a limitation on the implementation of the function.


Yes, but that limitation could be quite useful.
Consider having a function like this:

void foo(int bar)
{
int a = bar * 10;
if (a < 10){
b = 20 + bar;
}else {
a = 12 * bar * bar;
if (bar = 10 * a)
a -= bar * 5;
}
doStuff(a);
}

void
main(void)
{
foo(10);
}

// I'd like to add some code to the end of the function, testing the input parameter bar for some value:

void foo(int bar)
{
int a = bar * 10;
if (a < 10){
b = 20 + bar;
}else {
a = 12 * bar * bar;
if (bar = 10 * a)
a -= bar * 5;
}
doStuff(a);
// If bar input is 10 do some extra stuff.
if (bar == 10)
doExtraStuff(a);
}

void
main(void)
{
foo(10);
}






doExtraStuff is never executed in the later example, why?
Because there is an assignment to bar in the code.
Found it? if (bar = 10 * a)
To add code using bar, you need to serach the code to make sure that bar isn't modified somewhere.
With lot's of code, this takes time and it's quite easy to miss an assignment.
Using (const int bar) in the above, the code wouldn't compile without complaints.

Indeed my original intention wasn't to assign bar a new value, but rather doing a normal compare: if (bar == 10 * a)

Using the const keyword does clarify the intention of the code and can help you to avoid some logical bugs.

Just my 2c

Share this post


Link to post
Share on other sites
Quote:
Original post by eq
doExtraStuff is never executed in the later example, why?
Because there is an assignment to bar in the code.
Found it? if (bar = 10 * a)

Very clever! If only it wasn't such a mess to use the const keyword everywhere. If you stuck to this design rule, const would easily be the most frequently used word in your project, perhaps doubling other words. I think the language designers should have defaulted function parameters to const and gave us a modifiable keyword [smile]

Share this post


Link to post
Share on other sites
Passing const copies of objects (mostly basic types) makes it clear that this is a "read only" INPUT parameter, and that if the value is changed, it won't be propagated outside the scope of the function.

Now, if my parameter was const float in_fBlendTime, for example, and that I'd like, for some reason set the blend time to 0 on some condition, I'd rather have a float fBlendTime = in_fBlendTime; if(...) fBlendTime = 0.f; than to have a non-const parameter.

I guess that's a matter of taste.

Share this post


Link to post
Share on other sites
Quote:
Original post by Andrew Russell
Quote:
Original post by swiftcoder
But in theory at least, a "const int" can be optimized, because it is guarenteed not to be changed

No.

A non-const int is guarenteed not to change, because it's passed by value (a copy is made). Making it const dosn't provide any extra guarentees to the caller. It only places a limitation on the implementation of the function.

Which is the reason that the implementation can remove the const as b34r said in his first post. It is because the compiled code is exactly the same.


AFAIK, ANY variable declared 'const' is now a constant instead, and whether it is an argument of a temporary is immaterial. And at least in theory, a compiler can optimize constants (maybe by placing it in read-only cache memory, for instance).

Share this post


Link to post
Share on other sites
Quote:
Original post by Jiia
Quote:
Original post by eq
doExtraStuff is never executed in the later example, why?
Because there is an assignment to bar in the code.
Found it? if (bar = 10 * a)

Very clever! If only it wasn't such a mess to use the const keyword everywhere. If you stuck to this design rule, const would easily be the most frequently used word in your project, perhaps doubling other words. I think the language designers should have defaulted function parameters to const and gave us a modifiable keyword [smile]


In my language design, all input parameters are always const (although a Java/Python - like object model is used, so you can pass an object and modify the object via its interface - you can't change *which* object it is, but you could use an equivalent to operator=, for example).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this