Thread: strange std::map behavior

  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
    28,413
    To simplify the usage of the map in some cases. Where you do not want this behaviour, you would use member find().
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    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
    28,413
    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];
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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 08:48 AM.

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> 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
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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,366
    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
    28,413
    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));
        }
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  11. #11
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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,366
    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
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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
    Location
    Inside my computer
    Posts
    24,654
    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.

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, 07: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, 12:03 PM
  5. Strange behavior with CDateTimeCtrl
    By DonFiasco in forum Windows Programming
    Replies: 2
    Last Post: 12-19-2004, 02:54 PM