Actually I'm quite sure I've missed something trivial here, but I just can't find it.
Seemingly I cannot read from a const map&
I try -
#include <iostream>
-
#include <map>
-
using namespace std;
-
-
void show (
-
const // troubling-const
-
map<char, double>& myconstmap )
-
{
-
cout << "A->" << myconstmap['A'] << "\n";
-
}
-
-
int main ()
-
{
-
map<char, double> mymap;
-
mymap['A']=0.1;
-
}
-
-
If I remove the troubling const I'm able to access it but I don'r really feel like giving up on const
I'm thankful for any hint
J
12 5586
The const has nothing to do with it.
It's your use of operator[] in the the cout in line 9. That operator returns a reference to the map element. It's possible to change the map byusing this reference. Your const gets in the way of that and you get a compile error.
Either: a) don't use const or b) use const but don't use the map [] operator.
The const has nothing to do with it.
It's your use of operator[] in the the cout in line 9. That operator returns a reference to the map element. It's possible to change the map byusing this reference. Your const gets in the way of that and you get a compile error.
ok
Either: a) don't use const
mhh, I dont really feel like this is a solution, but rather a workaround which I dont feel comfortable with. The map is created in one spot and I want to hand it around and read it from multiple places without the possibility to change it.
or b) use const but don't use the map [] operator.
But as far as I can see the only other way to access the elements in the map then is the const_iterator which is not suitable for me - I rather would need some kind of random access.
Well, ok thanks for your answer.
Maybe map is just not the right thing here - I'll look for something else.
Thanks.
Why insist on map::operator[] ???
You can use map::find() instead. That will return the pair that has your key and value.
Otherwise, you can write a new map iof your own be deriving from map (bs sure map has a virtual destructor) and then write an operator[] in your map that returns a const value for the key rather than a const_iterator.
Please note, access in a map is not random, like an array. Access is based on a key and not and element number. The map::operator[] tries to make the map look like an array but it does return the value in a form that allows you to change it.
Why insist on map::operator[] ???
You can use map::find() instead. That will return the pair that has your key and value.
Because I dont want to do something in logarithmic time, when it should be done in constant time.
Otherwise, you can write a new map iof your own be deriving from map (bs sure map has a virtual destructor) and then write an operator[] in your map that returns a const value for the key rather than a const_iterator.
That sounds like a very interessting idea - I think I'll try that. Very interessting. I have never thought about deriving from some stl thing. mhh...
Please note, access in a map is not random, like an array. Access is based on a key and not and element number. The map::operator[] tries to make the map look like an array but it does return the value in a form that allows you to change it.
I don't get that. What I meant when I said random was that I can access an arbitrary element in constant time - independent of whether I'm allowed to change the element or not. And as I expect a map to be something like a hashtable and I know my keys will all be unique (Im not actually using char as indicated in my example but pointers to struct), I would expect [] to execute in constant time.
Although now that you made me think about it again I dont find any statement about execution time of [] in
http://www.cppreference.com/cppmap/map_operators.html
What I meant when I said random was that I can access an arbitrary element in constant time - independent of whether I'm allowed to change the element or not. And as I expect a map to be something like a hashtable and I know my keys will all be unique (Im not actually using char as indicated in my example but pointers to struct), I would expect [] to execute in constant time.
A map is a red-black binary tree. Access is not in constant time like an array.
All STL associative containers use red-black trees.
There is a hashmap but it is still non-standard.
A map is a red-black binary tree. Access is not in constant time like an array.
Ok, I see. So the execution times of both, operator[] and find() are logarithmic, right?
I think, I'm going to put the map into a wrapper that provides something like - TYPE& operator[]( const key_type& key );
-
const TYPE& operator[]( const key_type& key ) const;
Besides the satisfaction of my const-request this would allow me to change from map to whatever, maybe a hash table in the future.
Yes, you could change the implementation of the tree.
Generally, I advise to not expose your implementation for that very reason. All of these STL containers should be fronted by an access class of your design and with your interface methods.
Ditto for memory using new and delete. I always use a Create/Delete function and bury the allocation.
Errr, Im afraid Im back .... I tried to:
you can write a new map iof your own be deriving from map (bs sure map has a virtual destructor) and then write an operator[] in your map that returns a const value for the key rather than a const_iterator.
like this: -
#include <iostream>
-
#include <map>
-
using namespace std;
-
-
-
template < typename keytype, typename TYPE >
-
class cmap: public std::map<keytype, TYPE>
-
{
-
public:
-
virtual const TYPE& operator[](const keytype& k) const // this seems to keep me from accessing the non-const operator[]
-
//virtual const TYPE& get(const keytype& k) const
-
{
-
// get rid of const so we are able to call operator[]()
-
const cmap<keytype,TYPE>& const_cmap = *this;
-
const std::map<keytype,TYPE>& const_map = const_cmap;
-
std::map<keytype,TYPE>& nonconst_map = const_cast < std::map<keytype,TYPE>& > ( const_map );
-
// retrieve the element and return it as const&
-
return nonconst_map[k];
-
}
-
-
virtual ~cmap(){}
-
};
-
-
-
-
int main (){
-
-
cmap <char, double> mycmap;
-
mycmap['A'] = 0.2; // compile-error: "assignment of read-only location"
-
-
const cmap<char, double>& const_mycmap = mycmap;
-
cout << const_mycmap['A'] << "\n";
-
//cout << const_mycmap.get('A') << "\n";
-
}
This doesnt compile due to line 29, so seemingly I do have a const operator[] now, but the non-const operator[] is gone.
If I exchange line 15 with 16 and 37 with 38 it works, but well then there is still no const operator[]() const.
You have to write your own cmap::operator[]. One for non-const cmaps and one for const cmaps.
No amount casting is going to help you.
Here is my try. It compiles and links but I didn't test it. -
#include <iostream>
-
#include <map>
-
#include <exception>
-
using namespace std;
-
-
-
template < typename keytype, typename TYPE >
-
class cmap: public std::map<keytype, TYPE>
-
{
-
public:
-
TYPE& operator[](const keytype& k)
-
-
{
-
map::iterator theData = this->lower_bound(k);
-
if (theData == this->end())
-
{
-
exception obj("key not found");
-
throw obj;
-
-
-
}
-
return theData->second;
-
}
-
TYPE operator[](const keytype& k) const
-
-
{
-
map::const_iterator theData = this->lower_bound(k);
-
if (theData == this->end())
-
{
-
exception obj("key not found");
-
throw obj;
-
-
-
}
-
return theData->second;
-
}
-
virtual ~cmap(){}
-
};
-
-
-
-
int main (){
-
-
cmap <char, double> mycmap;
-
mycmap['A'] = 0.2; // compile-error: "assignment of read-only location"
-
-
const cmap<char, double>& const_mycmap = mycmap;
-
cout << const_mycmap['A'] << "\n";
-
//cout << const_mycmap.get('A') << "\n";
-
}
-
Lastly, the camp destructor does not need to be virtual unless you create a cmap and use it as a map* or map&. And if you do that, be sure the map destructor is virtual. If it's not, that the signal that map cannot be used polymorphically.
You have to write your own cmap::operator[]. One for non-const cmaps and one for const cmaps.
ok, I had never guessed that!
And - ok, learned something again - obviously it is not possible to return a const TYPE& if there is no such object. which finally is the answer to my unspelled question "why is the const TYPE& operator[]() const not already implemented in std::map?". But the exception is a nice resolution to this. I think it suits my needs quite well, since if my code ever tries to call const_mycmap[key] for some undefined key, it is a bug anyways and I'll be thankful for the exception.
But contrary to your proposal, I don't want an exception in the case of accessing an undefined key in the non-const context. E.g. line 45 of your code raises an exception. Also it changes the semantics of the base class std::map in a surprising way.
Additionally, I needed to change the declaration of the iterators and replace the exception object. But this might be subject to different compilers.
Below is the version that works for me and with which I feel quite satisfied. -
#include <iostream>
-
#include <map>
-
#include <exception>
-
using namespace std;
-
-
-
class message: public exception
-
{
-
protected:
-
string What;
-
public:
-
message( string m ): What(m) {}
-
~message() throw() {}
-
virtual const char* what() const throw() {
-
return What.c_str();
-
}
-
};
-
-
-
-
template < typename keytype, typename TYPE >
-
class cmap: public std::map<keytype, TYPE>
-
{
-
public:
-
-
TYPE& operator[](const keytype& k)
-
{
-
// use the operator[] of the base class map
-
return map<keytype,TYPE>::operator[](k);
-
}
-
-
-
const TYPE& operator[](const keytype& k) const
-
{
-
//map::const_iterator theData ; // g++ says:
-
// `template<class _Key, class _Tp, class _Compare, class _Alloc>
-
// class std::map' used without template parameters
-
// missing template arguments before "theData"
-
-
typename map< keytype, TYPE >::const_iterator theData ;
-
// took me a while to figure out that (for whatever reason) typename
-
// is required here
-
-
theData = this->lower_bound(k);
-
if ( theData == this->end() )
-
{
-
//exception obj("key not found"); // g++ says:
-
// no matching function for call to
-
// `std::exception::exception(const char[14])'
-
-
message obj("key not found");
-
throw obj;
-
}
-
return theData->second;
-
}
-
-
virtual ~cmap(){}
-
};
-
-
-
-
int main ()
-
{
-
-
try
-
{
-
cmap <char, double> mycmap;
-
mycmap['A'] = 0.2;
-
cout << mycmap['A'] << " {" << &(mycmap['A']) << "}\n";
-
-
const cmap<char, double>& const_mycmap = mycmap;
-
cout << const_mycmap['A'] << " {" << &(const_mycmap['A']) << "}\n";
-
cout << const_mycmap['B'] << "\n"; // raises an exception, which is good!
-
}
-
catch ( message e )
-
{
-
cout << "Exception: \"" << e.what() << "\"\n";
-
exit( EXIT_FAILURE );
-
}
-
}
-
bugfix: it should be
theData = this->find(k);
instead of
theData = this->lower_bound(k);
Post your reply Sign in to post your reply or Sign up for a free account.
Similar topics
5 posts
views
Thread by Mark Van Orman |
last post: by
|
5 posts
views
Thread by Evgeny |
last post: by
|
6 posts
views
Thread by scottyman |
last post: by
|
3 posts
views
Thread by asclearuc |
last post: by
| |
reply
views
Thread by subramanian100in |
last post: by
| | | | | | | | | | | |