472,779 Members | 1,593 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,779 software developers and data experts.

unable to read from const std::map<>&

63
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

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <map>
  3. using namespace std;
  4.  
  5. void show ( 
  6.   const // troubling-const
  7.   map<char, double>& myconstmap )
  8. {
  9.   cout << "A->" << myconstmap['A'] << "\n";
  10. }
  11.  
  12. int main ()
  13. {
  14.   map<char, double> mymap;
  15.   mymap['A']=0.1;
  16. }
  17.  
  18.  
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
Nov 29 '07 #1
12 5748
weaknessforcats
9,208 Expert Mod 8TB
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.
Nov 29 '07 #2
jabbah
63
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.
Nov 29 '07 #3
weaknessforcats
9,208 Expert Mod 8TB
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.
Nov 29 '07 #4
jabbah
63
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
Nov 29 '07 #5
weaknessforcats
9,208 Expert Mod 8TB
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.
Nov 30 '07 #6
jabbah
63
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
Expand|Select|Wrap|Line Numbers
  1. TYPE& operator[]( const key_type& key );
  2. 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.
Dec 3 '07 #7
weaknessforcats
9,208 Expert Mod 8TB
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.
Dec 3 '07 #8
jabbah
63
Thanks weaknessforcats
Dec 3 '07 #9
jabbah
63
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:

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <map>
  3. using namespace std;
  4.  
  5.  
  6. template < typename keytype, typename TYPE >
  7. class cmap: public std::map<keytype, TYPE> 
  8. {
  9. public:
  10.   virtual const TYPE& operator[](const keytype& k) const // this seems to keep me from accessing the non-const operator[]
  11.   //virtual const TYPE& get(const keytype& k) const 
  12.   {
  13.     // get rid of const so we are able to call operator[]()
  14.     const cmap<keytype,TYPE>& const_cmap = *this;
  15.     const std::map<keytype,TYPE>& const_map = const_cmap;
  16.     std::map<keytype,TYPE>& nonconst_map = const_cast < std::map<keytype,TYPE>& > ( const_map );
  17.     // retrieve the element and return it as const&
  18.     return nonconst_map[k];
  19.   }
  20.  
  21.   virtual ~cmap(){}
  22. };
  23.  
  24.  
  25.  
  26. int main (){
  27.  
  28.   cmap <char, double> mycmap;
  29.   mycmap['A'] = 0.2; // compile-error: "assignment of read-only location"
  30.  
  31.   const cmap<char, double>& const_mycmap = mycmap;
  32.   cout << const_mycmap['A'] << "\n";
  33.   //cout << const_mycmap.get('A') << "\n";
  34. }
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.
Dec 6 '07 #10
weaknessforcats
9,208 Expert Mod 8TB
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.
Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <map>
  3. #include <exception>
  4. using namespace std;
  5.  
  6.  
  7. template < typename keytype, typename TYPE >
  8. class cmap: public std::map<keytype, TYPE> 
  9. {
  10. public:
  11.     TYPE& operator[](const keytype& k)
  12.  
  13.   {
  14.       map::iterator theData = this->lower_bound(k);
  15.       if (theData == this->end())
  16.       {
  17.            exception obj("key not found");
  18.            throw obj;
  19.  
  20.  
  21.       }
  22.       return theData->second;
  23.   }
  24.   TYPE operator[](const keytype& k) const
  25.  
  26.   {
  27.       map::const_iterator theData = this->lower_bound(k);
  28.       if (theData == this->end())
  29.       {
  30.            exception obj("key not found");
  31.            throw obj;
  32.  
  33.  
  34.       }
  35.       return theData->second;
  36.   }
  37.   virtual ~cmap(){}
  38. };
  39.  
  40.  
  41.  
  42. int main (){
  43.  
  44.   cmap <char, double> mycmap;
  45.   mycmap['A'] = 0.2; // compile-error: "assignment of read-only location"
  46.  
  47.   const cmap<char, double>& const_mycmap = mycmap;
  48.   cout << const_mycmap['A'] << "\n";
  49.   //cout << const_mycmap.get('A') << "\n";
  50. }
  51.  
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.
Dec 6 '07 #11
jabbah
63
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.

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. #include <map>
  3. #include <exception>
  4. using namespace std;
  5.  
  6.  
  7. class message: public exception 
  8. {
  9. protected:
  10.   string What;
  11. public:
  12.   message( string m ): What(m) {}
  13.   ~message() throw() {}
  14.   virtual const char* what() const throw() {
  15.     return What.c_str();
  16.   }
  17. };
  18.  
  19.  
  20.  
  21. template < typename keytype, typename TYPE >
  22. class cmap: public std::map<keytype, TYPE> 
  23. {
  24. public:
  25.  
  26.   TYPE& operator[](const keytype& k) 
  27.   {
  28.     // use the operator[] of the base class map
  29.     return map<keytype,TYPE>::operator[](k);
  30.   }
  31.  
  32.  
  33.   const TYPE& operator[](const keytype& k) const 
  34.   {
  35.     //map::const_iterator theData ; // g++ says: 
  36.     // `template<class _Key, class _Tp, class _Compare, class _Alloc> 
  37.     // class std::map' used without template parameters
  38.     // missing template arguments before "theData"
  39.  
  40.     typename map< keytype, TYPE >::const_iterator theData ; 
  41.     // took me a while to figure out that (for whatever reason) typename 
  42.     // is required here
  43.  
  44.     theData = this->lower_bound(k);
  45.     if ( theData == this->end() )
  46.       {
  47.         //exception obj("key not found"); // g++ says: 
  48.         // no matching function for call to 
  49.         // `std::exception::exception(const char[14])'
  50.  
  51.         message obj("key not found");
  52.         throw obj;
  53.       }
  54.     return theData->second;
  55.   }
  56.  
  57.   virtual ~cmap(){}
  58. };
  59.  
  60.  
  61.  
  62. int main ()
  63. {
  64.  
  65.   try 
  66.     {
  67.       cmap <char, double> mycmap;
  68.       mycmap['A'] = 0.2; 
  69.       cout << mycmap['A'] << " {" << &(mycmap['A']) << "}\n";
  70.  
  71.       const cmap<char, double>& const_mycmap = mycmap;
  72.       cout << const_mycmap['A'] << " {" << &(const_mycmap['A']) << "}\n";
  73.       cout << const_mycmap['B'] << "\n"; // raises an exception, which is good!
  74.     }
  75.   catch ( message e )
  76.     {
  77.       cout << "Exception: \"" << e.what() << "\"\n";
  78.       exit( EXIT_FAILURE );
  79.     }
  80. }
  81.  
Dec 6 '07 #12
jabbah
63
bugfix: it should be

theData = this->find(k);

instead of

theData = this->lower_bound(k);
Feb 28 '08 #13

Sign in to post your reply or Sign up for a free account.

Similar topics

5
by: Mark Van Orman | last post by:
Hi all, I have an application that logs in xml. Assume <xmlLog></xmlLog>. In this element the app logs anything it gets from foreign hosts. Now if the host sends xml data, the structure of the...
5
by: Evgeny | last post by:
Hi, all! I try to convert my existing code written in VC6 to VC7 and have some problem with stl auto pointer template. class CColumn; #include <memory> typedef auto_ptr<CMyBase> CMyBasePtr; ...
6
by: scottyman | last post by:
I can't make this script work properly. I've gone as far as I can with it and the rest is out of my ability. I can do some html editing but I'm lost in the Java world. The script at the bottom of...
3
by: asclearuc | last post by:
Hello Is it possible to use map<string&, string&>? Why I need it. I have a large amount of data obtained from XML file. I should do processing of this data. The processing takes many...
3
by: markoj | last post by:
hi i HAVE WRITTEN A perl script that will search a file and print output I have created a simple html doc i want to be able to click a link and it will print the output in of a specific file so i...
0
by: subramanian100in | last post by:
consider the following program: #include <cstdlib> #include <iostream> #include <map> #include <utility> #include <string> using namespace std;
0
by: TrevRex | last post by:
Hello, I work for a non-profit in San Diego as a GIS Specialist. I have had to teach myself about some scripting to create some dynamic maps, but I am still very limited in my skills, so I have...
0
by: Rina0 | last post by:
Cybersecurity engineering is a specialized field that focuses on the design, development, and implementation of systems, processes, and technologies that protect against cyber threats and...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
by: erikbower65 | last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps: 1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal. 2. Connect to...
0
by: Taofi | last post by:
I try to insert a new record but the error message says the number of query names and destination fields are not the same This are my field names ID, Budgeted, Actual, Status and Differences ...
14
DJRhino1175
by: DJRhino1175 | last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this - If...
0
by: Rina0 | last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
5
by: DJRhino | last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer) If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _ 310030356 Or 310030359 Or 310030362 Or...
0
by: Mushico | last post by:
How to calculate date of retirement from date of birth
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.