Recently i was looking for a solution to sort only the values of map and then i found this code
template <typename T1, typename T2>
struct less_second {
typedef pair<T1, T2> type;
bool operator ()(type const& a, type const& b) const {
return a.second < b.second;
}
};
map<string, int> mymap;
// …
vector<pair<string, int> > mapcopy(mymap.begin(), mymap.end());
sort(mapcopy.begin(), mapcopy.end(), less_second<string, int>());
The first thing that stuck my mind was why in many sample code and solutions I find people frequently using the const keyword is it a good practice to do that, if so why?
Why use const?
My take is that you should try to use const as much as you can. Mutable values are always a source of errors. You can avoid these errors by avoiding mutable values.
Function of const in C++
const is used a lot because it has a lot off different meanings:
If we look at this signature, we can see two types of const bool operator ()(type const& a, type const& b) const {...}: There is a const reference const &a and const &b, which just means that you cannot modify a or b, which you passed as reference.
There is also the const at the end of the method, which means that this method does not modify the instance. Figure a get-method. This method will not modify the instance it gets the value from. You can signal this to the caller by using T get_element(int at_index) const {...}.
There are further const pointers.
Here you could change the value in the address, but not the address itself:
int *const a = new int;
*a = 1; // legal
a = &var; // illegal
Here you can change the address the pointer is pointing to, but not the value in that address.
const int *a = new int;
*a = 1; // illegal
a = &var; // legal
(Hope I did not confuse the two)
Have a pointer that does not allow any change:
const int * const a = new int;
*a = 1; // illegal
a = &var; // illegal
Further reading:
When to use constant pointers instead of const references.
YT - Const in C++
There is furthermore constexpr, which can calculate a value at compile time. This is different than the const keyword, and might confuse you at the beginning.
The const in the parameters of this function allows the function to be called with const values (in the case of int a value like 1 is const). And also since the parameters are a reference, the const guarantees that the original variables will not be changed.
The const after the member function declaration, guarentees that an object of that class is not modified when that function is called.
So by looking at the definition of the function, we can automatically know the guarentees and what type of variables we can use.
Also knowing these assumptions, the compiler can create better code.
Related
Given
int i = 42;
int* p = &i;
we cannot do
const int * & d = p;
In my current understanding, this is because const int * & d can be read as "d is a reference of a pointer to an int that is a const" and p is "a pointer to an int", which means the RHS needs to be turned into a temporary being "a pointer to an int that is a const" and that cannot be binded directly with a reference (as on the LHS). We would need to have, say, const int* const& d = p;. Possible references: 1, 2.
That said, consider the following toy code:
template<typename T>
class X
{
public:
void fun(const T& d) { }
};
At first, I thought if I do
X<int*> x;
x.fun(p);
The method generated by the compiler would be void fun(const int*& d), and I would get an error due to the above reason.
However, there is no error and it works "as expected" (by that I mean, we always have d itself as the const no matter T is replaced by pointer types or by non-pointer types).
My current guess is that, for the above scenario, the method generated by the compiler is something like void fun(int* const& d).
May I ask if my guess is correct? How are templates work so that the classes generated by the compiler work with pointers "as expected"?
Your guess is correct.
For const T, const is qualified on type T directly. Given T is int* (non-const pointer to non-const int), const T results in const pointer, i.e. int* const (const pointer to non-const int) but not const int* (non-const pointer to const int).
Why const PointerToNonConst& value is understood as A* const for the code below:
using PointerToNonConst = A*; // or typedef A* PointerToNonConst;
const PointerToNonConst& value; // compiled and understood as `A* const`
I have expected it to be read-only pointer instead on constant pointer.
BTW here is a use-case, why you may meet this in your code:
class A
{
public:
void callOnNonConstMethodIsValid()
{
// change the object here
}
}
std::vector<A*> vect;
for (const auto& elem : vect)
{
elem->callOnNonConstMethodIsValid(); // no error
}
typedef and using are not like #define. It is not text replacement. When you make a type alias with typedef or using, that name is then treated as a single unit. When you apply const to it, it applies the type as a whole, at top level. You cannot apply it to inner components of that type.
Given
using NonConstPtr = A*; // or typedef A* NonConstPtr;
The declaration
const NonConstPtr& value = <initializer>;
is equivalent to
A* const& value = <initializer>;
value is a reference to a const pointer to an object of type A.
It is not equivalent to:
const A*& value = <initializer>;
where value is a reference to a pointer to const A.
This is one of the cases where it makes more sense to use the const keyword after the type.
NonConstPtr const& value = <initializer>;
If you do that, it might make more sense why the first interpretation is correct.
So Wikipedia tells me (correctly i believe) that to stop the editing of the data of a pointer and the pointer itself that I should do this:
void function(int const * const var)
Is this the same as this function:
void function(const int * const var)
And in that case why is it allowed? Because I know that you cant do this because of duplicate const compile error:
void function(const int const * const var)
I essentially want to do the same with a boost pointer. Would I do this:
void function(const boost::shared_ptr<int> const var)
And how would this affect my ability to loop over say a shared pointer to a vector? Could I do this with that guard:
void function(const boost::shared_ptr<std::vector<int>> const var)
{
for (unsigned int i = 0; i < var->size(); ++i)
{
std::cout << var[i];
}
}
Adition: After Brian's answer
So if I create a a pointer like this:
boost::shared_ptr<vector<int>> lala
And i use it in this function:
function (const boost::shared_ptr<std::vector<const int>> var)
will that work?
Yes, int const * const var is the same as const int * const var. You can put const before or after the type it modifies, for "historical reasons". See http://www.stroustrup.com/bs_faq2.html#constplacement
For a smart pointer object, you indeed cannot do
const boost::shared_ptr<int> const
because both consts modify the same type. Instead, you want
const boost::shared_ptr<const int>
The first const prevents the pointer itself from being modified (i.e., reassigned to point to another int) and the const in the template parameter tells the object's operator* to return a const int&, which prevents modification of the int pointed to.
This does not prevent iteration over a vector or other container in the manner you have described, for the same reason why you can still iterate over a const vector normally.
Edit in response to question edit:
This works:
void f(const boost::shared_ptr<const std::vector<int> > var);
// ...
boost::shared_ptr<vector<int> > lala;
f(lala);
The first const in the parameter doesn't affect parameter passing at all; it only tells the function itself not to modify the parameter. The reason why we can add a const in the template parameter is that a boost::shared_ptr<T> can be initialized from boost:shared_ptr<U> where T and U are not necessarily the same type, as long as U* is implicitly convertible to T*. If T is the same as U except with greater cv-qualification, as in this case, the conversion is possible.
Don't do std::vector<const int>. I'm fairly sure that's not legal. (At least I've gotten multiple screens of compilation errors every time I've tried it.)
const before or after the int is the same so:
int const * var
and
const int * var
are the same and mean the value pointed to cannot be changed
const after the * means that the pointer cannot be reassigned.
If I understand correctly, you'd like to make the vector const. If that's the case the syntax would be this:
void function(const boost::shared_ptr<const std::vector<int>>& var)
The smart pointer is passed by const reference because it's cheaper than passing the smart pointer by value and has the same effect. The object pointed to by the smart pointer is immutable by declaring the type it points to as const.
You've correctly reasoned that const shared_ptr<Foo> doesn't make Foo a const object. This "loophole" is described on wikipedia. Instead, you need to change the pointer type stored by boost::shared_ptr. This can be done in the template argument itself:
void function(const boost::shared_ptr<const std::vector<int>>& var)
boost::shared_ptr has a copy-constructor that allows for a const-type to be copied from a non-const-type. The opposite should not be possible.
Before, or after?
The below two lines are semantically equivalent, both declare a pointer which value cannot be changed, that refers to an int that cannot be changed.
int const * const p1 = ...;
const int * const p2 = ...;
The const keyword binds to whatever is directly to the left, unless there's nothing to the left, in which case it will hug whatever is on the right.
The more const, the better?
typedef boost::shared_ptr<int> shared_int_ptr;
const shared_int_ptr const p3; // ill-formed
The above typedef is provided to make it easier to see that boost::shared_ptr<int> is a single name, and therefore we cannot add const on both sides; duplicate consts are (as you mentioned) not legal C++.
Just applying one wouldn't be sufficient either, since that would make the wrapper const, but not the internal object that it is referring to (the int).
Previously we wrote that boost::shared_ptr should wrap around an int, but since we want to make the wrapped type const, well.. let's wrap the shared_ptr around what we want:
void func (const boost::shared_ptr<const int> foo);
In the above func is not able to modify foo, nor the int referred to by foo.
Please explain const void *a, const void *b on the code bellow. Are these constant reference parameters - meaning the inner code of this function cannot change its value? Why make these parameters a reference? Thought a reference parameter is meant to be for pass by value and allow value to be change inside the function definition. Why use void for a parameter argument?
int peak_compare(const void *a, const void *b) //Function peak_compare
{
Peaks *aa = (Peaks *)a;
Peaks *bb = (Peaks *)b;
if(aa->wt1 > bb->wt1) return -1;
if(aa->wt1 == bb->wt1) return 0;
return 1;
}
Thanks for any advise.
const typename * p is the syntax for Pointer to Constant. This means that, you cannot change the value in the function.
typename * const p is the syntax for Constant Pointer. This means that you cannot change the pointer itself in the function.
In the above examples, typename can be anything from standard types to user defined types, to void. If it is a void, the intention is that the function might get pointers to different types. You should properly cast the void pointer to correct type in order to access its members, as in your case the following lines are doing:
Peaks *aa = (Peaks *)a;
Peaks *bb = (Peaks *)b;
But this cast loses the const-ness. The correct syntax should be:
const Peaks *aa = (const Peaks *)a;
const Peaks *bb = (const Peaks *)b;
not to lose the value const-ness.
EDIT:
As one of the comments point out, and since the question is only tagged with C++, the cast is better done in C++ style as follows:
const Peaks* aa = static_cast<const Peaks*>(a);
const Peaks* bb = static_cast<const Peaks*>(b);
const void *a means a is a void pointer to constant, so the content cannot be change.
See this link for explanation:
http://en.wikipedia.org/wiki/Const-correctness
BUT there is a dangerous cast after as you loose the const content with your cast.
Peaks *aa = (Peaks *)a;
Should be changed to
const Peaks *aa = (const Peaks *)a;
Compare two void pointers, returning an integer greater than, equal to, or less than 0, according to whether the key of a is greater than, equal to, or less than the key of b as determined by comparing them with peak_compare().
There is no type safety while using arguments of type void* whether it's const or not. You should avoid using C-style casts as much as possible.
Peaks* aa = (Peaks*) a;
might lead to aa being invalid, which will result into undefined behavior.
In case you need this function because of qsort, then I recommend you to use std::sort instead.
In that case you could just override the operator< of Peaks:
struct Peaks
{
bool operator < (const Peaks& p) const
{
return (wt1 < p.wt1);
}
};
which could be possibly used like this:
std::vector<Peaks> vec;
...
std::sort(vec.begin(), vec.end());
Also have a look at Sorting a vector of custom objects :)
They are pointers to constant data, correct, see here so you cannot change the value of the thing they point to through the pointer.
The title is self explanatory, but I'll give an example anyways.
int sum(int a, int b){
return a + b;
}
We could rewrite it as
int sum(const int a, const int b){
return a + b;
}
But what about returning a const int? Is it useful in any way?
const int sum(const int a, const int b){
return a + b;
}
The caller will have to copy the const return to a const lvalue. Is this too restrictive? Do you know any use cases where this could be a good design choice?
Ok, I wasn't clear at the question body. Think about a sum function that works similar to assembly add:
int *sum(int *a, int b){
*a += b;
return a;
}
Add the const's to the params:
int *sum(int * const a, const int b){
*a += b;
return a;
}
What about making the return const too? Is there a reason for this?
There are a lot of situations where you may return a const pointer or a const object. I can't imagine any real situation where you want to return a primitive type as const.
I'm not sure what's your question, in the title your' talking about int* const but in the code example you have a const int.
Some examples (in C++) follows for different combinations of const and T*.
Pointer to const (primitive type)
const int* someFuncion();
You have a pointer to a constant, it means you can change the pointer but you can't change the pointed object/value. Please note that someFunction() must not return a pointer (const or not) to a stack allocated variable. I assume the pointer is valid. For example:
const int* value = someFunction();
// Next line is valid, value will hold a new pointer
value = anotherFunction();
// Next line is not valid, pointed value cannot be changed
*value = 10;
Pointer to const (object)
const T* someFunction();
You have a pointer to a constant. It means you can change the pointer to point to another object but you can't change the pointed object state. This doesn't mean you can't use that object, only that the object is const then you can use only its methods marked as const, read its fields and write its mutable fields. A constant method is defined as:
void method() const;
It can have any return type and any parameter the point is that it's marked with the const modifier. It means that it won't change the object state (again with the exclusion of mutable objects).
Now an example, with T declared as:
class T
{
public:
void dump() const
{
// Dump the value to console, for example
}
void increaseValue()
{
++m_value;
}
private:
int m_value;
};
Imagine to write following code:
const T* value = someMethod();
// Next line is valid, value will hold a new pointer
value = anotherMethod();
// Next line is not valid, we cannot change the object state
value->increaseValue();
// Next line is valid, we do not change the object state
value->dump();
Constant pointer (primitive type)
int* const someFunction();
You have a constant pointer, it means you can change the pointed value but you cannot assign another memory location to the pointer itself. For example:
int* const value = someFunction();
// Next line is not valid, value cannot be changed
value = anotherFunction();
// Next line is valid, you can change the variable pointed by value
*value = 10;
Constant pointer (object)
T* const someFunction();
You have a constant pointer, it means you can change the pointed object state but you cannot assign another memory location to the pointer itself. For example:
T* const value = someFunction();
// Next line is not valid, value cannot be changed
value = anotherFunction();
// Next lines are both valid, we can do whatever we want with the object
value->increaseValue();
value->dump();
Constant pointer to a constant
const int* const someFunction();
This is the mix of previous declarations. All (restrictive) rules described above are valid. It means you can't change the pointer and you can't change the pointed value.
Notes
The const modifier is not restricted to be used to pointers and functions return value. For example:
// PI value cannot be changed
const int PI = 3.14f;
// I have a pointer to a constant value
const* int pPI = &PI;
// I have a constant pointer to a constant value, note that
const* int const pPI2 = &PI;
Remember that the const modifier can always be removed using a C-style cast or a const_cast.
Conclusions
So, going back to your question, is it useful a function with a const int return value?
If it's a pointer my answer is yes, even if it can be removed with a cast: the purpose of const is to communicate intentions (saving you from stupid errors hard to find) so more your function communicates and better it'll be used. Updating this from your last example my answer is yes, use const wherever appliable. Who will call your code will thank you (and you'll do it with yourself).
If it's just a const int (or another primitive type) it may be very rare you have to write something like that. Very often they're just intermediate results of a long calculation then it's useless to declare them as const (primitive types won't change but will be combined to create a new value). Note, however, that if it make some sense to declare them as const then you should do it. I guess it's more common to see a constant primitive type declared as local variable (again to be sure it won't be changed by mistake). For example:
// This local variable cannot be modified
const int rate = (calculateX() + calculateY()) / calculateRateFactor();
Or in functions, why not? If you always use this rule (const if shouldn't be changed) you'll see on-the-fly when a parameter isn't const then you'll understand you'll modify it somewhere (maybe with a small, hidden, pretty ++ at the most right character of your screen).
// With this prototype I'm sure I won't change a or b by mistake inside
// the function body.
int someFunction(const int a, const int b);
For objects I think it's even more common to use the const modifier (because a const T return type makes sense very often), for example:
// This object cannot be changed, just moved all around
const order* getNextOrderToStore();
Topic isn't ended, of course, because of aliases, mutables, operators overloading and the differences between C and C++...
I can only see this as a good thing as a statement of intent.
Something more in the sense of - if you get this value, you shouldn't need to change it, more than don't change this value.
This actually accomplishes nothing other than intent, as you're able to change the value anyway: http://ideone.com/Mf8Ge
No, I see few situations where this would be useful, as it really accomplishes nothing, and it restricts what the caller can do with the return value.
The caller will have to copy the const return to a const lvalue.
No, it won't at all. In fact, it might not ever copy it. Or it might copy it to a mutable lvalue.
There is no sense in const rvalues, there never has been, and there never will be.