What is difference between const and non const key?
int
andconst int
are two distinct types.std::map<int, float>
andstd::map<const int, float>
are, similarly, different types.
The difference between std::map<const int, float>
and std::map<int, float>
is, to a degree, analogous to the difference between, say, std::map<int, float>
and std::map<std::string, float>
; you get a fresh map type for each.
In the non-const
case, the internal key type is still non-const
int
:
std::map<const int, float>::key_type => const int
std::map<int, float>::key_type => int
However, map keys are semantically immutable, and all map operations that allow direct access to keys (for example, dereferencing iterators, which yields value_type
) does const
ify the key_type
:
std::map<const int, float>::value_type => std::pair<const int, float>
std::map<int, float>::value_type => std::pair<const int, float>
So the difference may be largely invisible to you in every way that matters, if your implementation allows it.
That's not always the case, though: the standard officially requires your key type to be copyable and moveable, and some implementations re-use map nodes; under those implementations, attempting to use a const
key simply won't work.
C++ Difference Between Const Reference to Non Const Object and Non Const Reference to Non Const Object
"What is the purpose for the "const" keyword for a reference if the object it is referencing is not a const object?"
The purpose is to prevent that reference being used to modify the object it is referencing.
int i = 42; // non const object
const int &r1 = i; // const reference to non const object
r1 = 6 * 9; // error, r1 cannot be used to modify i;
Difference between const map and map of const elements
Having a const
container means the container is immutable. You can't change it.
Having a non-const
container means the container is mutable. You can change it.
Changing a map means: adding to it, modifying the things it contains (if they are, themselves, mutable), removing from it.
By the way, putting const
on a map key is largely pointless.
I'm not going to enumerate "when should each be used"; you use the right tool for the job, and there are a near-infinite number of possible jobs.
What is the difference between const int*, const int * const, and int const *?
Read it backwards (as driven by Clockwise/Spiral Rule):
int*
- pointer to intint const *
- pointer to const intint * const
- const pointer to intint const * const
- const pointer to const int
Now the first const
can be on either side of the type so:
const int *
==int const *
const int * const
==int const * const
If you want to go really crazy you can do things like this:
int **
- pointer to pointer to intint ** const
- a const pointer to a pointer to an intint * const *
- a pointer to a const pointer to an intint const **
- a pointer to a pointer to a const intint * const * const
- a const pointer to a const pointer to an int- ...
And to make sure we are clear on the meaning of const
:
int a = 5, b = 10, c = 15;
const int* foo; // pointer to constant int.
foo = &a; // assignment to where foo points to.
/* dummy statement*/
*foo = 6; // the value of a can´t get changed through the pointer.
foo = &b; // the pointer foo can be changed.
int *const bar = &c; // constant pointer to int
// note, you actually need to set the pointer
// here because you can't change it later ;)
*bar = 16; // the value of c can be changed through the pointer.
/* dummy statement*/
bar = &a; // not possible because bar is a constant pointer.
foo
is a variable pointer to a constant integer. This lets you change what you point to but not the value that you point to. Most often this is seen with C-style strings where you have a pointer to a const char
. You may change which string you point to but you can't change the content of these strings. This is important when the string itself is in the data segment of a program and shouldn't be changed.
bar
is a constant or fixed pointer to a value that can be changed. This is like a reference without the extra syntactic sugar. Because of this fact, usually you would use a reference where you would use a T* const
pointer unless you need to allow NULL
pointers.
const vs non-const variable with no change in value once assign
A clever compiler can understand that the value of a variable is never changed, thus optimizing the related code, even without the explicit const
keyword by the programmer.
As for your second, question, when you mark a variable as const
, then the follow might happen: the "compiler can optimize away this const by not providing storage to this variable rather add it in symbol table. So, subsequent read just need indirection into the symbol table rather than instructions to fetch value from memory". Read more in What kind of optimization does const offer in C/C++? (if any).
I said might, because const
does not mean that this is a constant expression for sure, which can be done by using constexpr
instead, as I explain bellow.
In general, you should think about safer code, rather than faster code when it comes to using the const
keyword. So unless, you do it for safer and more readable code, then you are likely a victim of premature optimization.
Bonus:
C++ offers the constexpr
keyword, which allows the programmer to mark a variable as what the Standard calls constant expressions. A constant expression is more than merely constant.
Read more in Difference between `constexpr` and `const` and When should you use constexpr capability in C++11?
PS: Constness prevents moving, so using const too liberally may turn your code to execute slower.
Both const and non-const version of the same function - an anti-pattern?
No, not always.
There are legitimate uses for this pattern. For example, suppose you are writing a collection, and the code for retrieving an element is fairly complex (e.g. a hash table). You don't want to duplicate all the code, but you also want your collection to be able to be used as both const and non-const.
So, you might do something like this:
struct HashTable {
...
const Value &get(Key key) const {
... complex code for retrieving the key
}
Value &get(Key key) {
return const_cast<Value &>(
static_cast<const HashTable *>(this)->get(key)
);
}
};
Here, the const_cast<>
is not really a lie. Since your function is non-const
, you know that it can be called only if the object pointed to by this
is also non-const. Hence, casting the constness away is valid.
(of course, similarly to this situation, you can call a non-const
method by casting away the const
-ness of a const
instance, but at that point its the user of your class who has already introduced undefined behavior, so you are covered as long as your class is being used correctly.)
How to find by a const pointer key in a map with non-const pointer keys
I think I have found a solution, but it requires C++14 transparent comparators.
#include <map>
#include <iostream>
struct CompareIntPtrs
{
using is_transparent = void; // enabling C++14 transparent comparators
bool operator()(const int * l, const int * r) const
{
return l < r;
}
};
std::map<int*, double, CompareIntPtrs> mymap;
double myfind(const int * key)
{
return mymap.find(key)->second;
}
int main()
{
int x {6};
mymap[&x] = 66; // inserting to the map
const int * px = &x; // creating a "const int *" variable
std::cout << myfind(px) << std::endl; // using "const int *" for finding in map with "int*" keys
std::cout << mymap.find(px)->second << std::endl; // we could even skip using myfind()
}
An excellent article about C++14 transparent comparators can be found here.
To be completely honest, by adding the comparator, the type of mymap
slightly changed which I originally didn't want to, but it's the best solution I could find.
If C++14 is not available, there are at least two evils we can choose from.
The first one is to copy mymap
to a new std::map<const int*, double>
in myfind
, which is horribly unefficient.
The second one is casting away constness by using a const_cast<int*>(mykey)
which should be avoided if possible.
Copy paste of const and non-const methods
This is one of the legitmate uses of const_cast
const std::string* get(ID id) const override
{
return const_cast<ConcreteStorage*>(this)->get(id);
}
Why can I pass the key of std::map to a function that expects non-const?
so I assume that the type of
elem.first
isconst S*
No. The key stored in map
is const
, that means for std::map<S*, Data>
, the key will be S* const
(i.e. const
pointer), not const S*
(i.e. pointer to const
). So it's fine to pass it to foo(S* ptr)
, the const
pointer itself will be copied to the parameter.
Related Topics
Best Practices for Use of C++ Header Files
Performance Degradation Due to Default Initialisation of Elements in Standard Containers
Search 25 000 Words Within a Text
Is It a Good Practice to Use Unions in C++
In C/C++ Why Does the Do While(Expression); Need a Semi Colon
How to Find the 'Temp' Directory in Linux
Creating a Lock That Preserves the Order of Locking Attempts in C++11
Less Verbose Way to Declare Multidimensional Std::Array
What Does 'Value Initializing' Something Mean
C++ Trying to Get Function Address from a Std::Function
Propagate Constness to Data Pointed by Member Variables
C++ Template Instantiation: Avoiding Long Switches
Call of Overloaded Function Is Ambiguous
Any Way Faster Than Pow() to Compute an Integer Power of 10 in C++