strange std::map behavior

This is a discussion on strange std::map behavior within the C++ Programming forums, part of the General Programming Boards category; map: perator[] public member function T& operator[] ( const key_type& x ); Access element If x matches the key of ...

  1. #1
    Banned
    Join Date
    Nov 2007
    Posts
    678

    strange std::map behavior

    map:perator[] public member function

    T& operator[] ( const key_type& x );

    Access element

    If x matches the key of an element in the container, the function returns a reference to its mapped value.

    If x does not match the key of any element in the container, the function inserts a new element with that key and returns a reference to its mapped value. Notice that this always increases the map size by one, even if no mapped value is assigned to the element (the element is constructed using its default constructor).
    Why insert a new element and return a default value? Why not just raise an exception here? This really seems bad.

    On a side note: Ditto behavior in Qt's QMap as well. Why such practice?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,256
    To simplify the usage of the map in some cases. Where you do not want this behaviour, you would use member find().
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Banned
    Join Date
    Nov 2007
    Posts
    678
    absolutely silly behavior i think.
    thank god that Python handles it better
    Code:
    m = { 1:'uno', 2:'duo' }
    print m[3]
    
    Traceback (most recent call last):
      File "<pyshell#2>", line 1, in <module>
        m[3]
    KeyError: 3

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,256
    absolutely silly behavior i think.
    Consider this code snippet that counts the frequency of words in a vector:
    Code:
    std::map<std::string, std::size_t> word_count;
    for (std::vector<std::string>::const_iterator i = words.begin(),
         end = words.end(); i != end; ++i)
    {
        ++word_count[*i];
    }
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,270
    Quote Originally Posted by manav View Post
    Why insert a new element and return a default value? Why not just raise an exception here? This really seems bad.
    How the heck could this work:

    Code:
    map[x] = y;
    Unless map[x] returned a non-const reference? And how can map[x] possibly return a non-const reference without ensuring that the element exists?

  6. #6
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,270
    Quote Originally Posted by manav View Post
    absolutely silly behavior i think.
    thank god that Python handles it better
    Uh, C++ is not Python.

    operator[] is a convenience function. If you do not want to accidentally construct an element, use find() instead of operator[].

    The problem is how you are trying to use the tool, not the tool itself.

    EDIT: Also, having operator[] works different in l-value contexts vs. r-value contexts is simply not possible in C++. It MUST return a non-const reference, which means the element MUST exist.
    Last edited by brewbuck; 04-10-2008 at 09:48 AM.

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    >> And how can map[x] possibly return a non-const reference without ensuring that the element exists?
    By throwing an exception if the element is not found?

    But I agree that the current behavior makes sense and is very useful.

  8. #8
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,270
    Quote Originally Posted by Daved View Post
    >> And how can map[x] possibly return a non-const reference without ensuring that the element exists?
    By throwing an exception if the element is not found?
    That would render operator[] completely pointless. If you had to insert() an element before accessing it with operator[], then the only possible use of operator[] would be for lookup. I hardly see the point of even having an operator[] unless I can do this:

    Code:
    a[b] = c;

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    I'm not arguing with you about the usefulness of the feature, but you're point doesn't make sense. The vector class has similar syntax, and it isn't pointless.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    22,256
    That would render operator[] completely pointless. If you had to insert() an element before accessing it with operator[], then the only possible use of operator[] would be for lookup. I hardly see the point of even having an operator[] unless I can do this:
    You certainly would be able to do that, just that there has to be a valid key with b's value already in the map. It would just make it inconvenient for insertion, so my example would become the rather horrible:
    Code:
    for (std::vector<std::string>::const_iterator i = words.begin(),
         end = words.end(); i != end; ++i)
    {
        try
        {
            ++word_count[*i];
        }
        catch (const std::out_of_range& e)
        {
            word_count.insert(std::make_pair(*i, 1));
        }
    }
    ... which would be about the same as just writing:
    Code:
    for (std::vector<std::string>::const_iterator i = words.begin(),
         end = words.end(); i != end; ++i)
    {
        std::map<std::string, std::size_t>::iterator iter = word_count.find(*i);
        if (iter != word_count.end())
        {
            ++iter->second;
        }
        else
        {
            word_count.insert(std::make_pair(*i, 1));
        }
    }
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,270
    Quote Originally Posted by Daved View Post
    I'm not arguing with you about the usefulness of the feature, but you're point doesn't make sense. The vector class has similar syntax, and it isn't pointless.
    Well, two responses to that:

    1. For std::vector, operator[] is much more necessary than for std::map. A vector inherently "keys" its contents by their indices. Whereas with std::map, operator[] exists only for convenience, and the container would still be quite usable without it.

    2. The original argument was, should operator[] throw an exception when accessing an out-of-bounds key or index. The answer, for both std::vector and std::map, is no. It's not valid to go out of bounds on a vector, but it doesn't throw an exception when you do it.

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    It would be a completely valid interface if it did, though. The at() function throws an exception, why couldn't an operator[]?

    Your first point backs me up. The operator[] exists only for convenience, so a slightly less convenient usage would not be pointless, just less convenient.

  13. #13
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,270
    Quote Originally Posted by Daved View Post
    It would be a completely valid interface if it did, though. The at() function throws an exception, why couldn't an operator[]?
    Because the only difference between the two is whether it throws?

    Your first point backs me up. The operator[] exists only for convenience, so a slightly less convenient usage would not be pointless, just less convenient.
    Decreasing the convenience of a convenience function makes it not a convenience function anymore, IMHO, simply a redundant one.

    EDIT: Eh, I have a feeling I'm being obnoxious.

  14. #14
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    Although using the operator[] in a vector can produce undefined behavior if the specified element does not exist.

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Posts
    22,985
    And thank goodness Microsoft created a safe-guard for that. By default, it throws and assert if an out-of-bound access is made, in debug.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Page 1 of 5 12345 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Strange string behavior
    By jcafaro10 in forum C Programming
    Replies: 2
    Last Post: 04-07-2009, 08:38 PM
  2. C++ list Strange Behavior
    By yongzai in forum C++ Programming
    Replies: 19
    Last Post: 12-29-2006, 02:56 AM
  3. Strange behavior of Strings
    By shyam168 in forum C Programming
    Replies: 9
    Last Post: 03-27-2006, 07:41 AM
  4. strange behavior
    By agarwaga in forum C Programming
    Replies: 1
    Last Post: 10-17-2005, 01:03 PM
  5. Strange behavior with CDateTimeCtrl
    By DonFiasco in forum Windows Programming
    Replies: 2
    Last Post: 12-19-2004, 02:54 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21