C ++: How can I stop the map operator [] from inserting dummy values?

My code did the following:

  • Get value from mapusing operator[].
  • Check the return value, and if NULLuse insert, to insert a new item into the map.

Magically, an element with a value appeared on the map 0.

After hours of debugging, I found the following: map operator[] inserts a new element if the key is not found , while it insert does not change the value if the key exists .

Even if the default constructor for the map value type does not exist, compiling the code and operator[]inserts 0.

Is there any way (for example, some kind of coding convention with which I could follow now) that I could prevent this from harming me?

+3
source share
8 answers

Is there any way (for example, some kind of coding convention with which I could follow now) that I could prevent this from harming me?

This may sound funny, but: after reading the documentation.

Since what you did is the somewhat expected behavior of the card, you cannot do it to protect it.

In the future, the following may be considered. In the second step, you did something wrong:

Check the return value, and if NULL use insert to insert a new element on the map.

, ++ ( C new): , - , NULL ( 0 nullptr) . ( , operator [] . obvoiusly (, )).

, , , , , end() .

, ( NULL), NULL, , 0 ++, .

++ 11 , nullptr, , . , : NULL, ++ 11 nullptr.

+6

, , , .

find().

+7

, operator [], , -.

, , find:

if ( mymap.find(myKey) == mymap.end() )
{
    //the key doesn't exist in a map
}

, operator [], NULL, ( , value 0, NULL).

+4

. operator[] , . .

insert .

+4

std:: map - .at(const Key& key), std::out_of_range, .

http://en.cppreference.com/w/cpp/container/map/at

+1

[] find . , . .

0

, , , ..

class Foo
{
    // Use a typedef so we can conveniently declare iterators
    // and conveniently construct insert pairs
    typedef map<int, std::string> IdMap;
    IdMap id_map;

    // A function that looks up a value without adding anything
    void one(int id)
    {
        IdMap::iterator i = id_map.find(id);

        // See if an entry already exists
        if (i == id_map.end())
            return; // value does not exist

        // Pass the string value that was stored in the map to baz
        baz(i->second);
    }

    // A function that updates an existing value, but only if it already exists
    bool two(int id, const std::string &data)
    {
        IdMap::iterator i = id_map.find(id);

        if (i == id_map.end())
            return false;

        i->second = data;
        return true;
    }

    // A function that inserts a value only if it does NOT already exist
    // Returns true if the insertion happened, returns false if no effect
    bool three(int id, const std::string &data)
    {
        return id_map.insert(IdMap::value_type(id, data)).second;
    }

    // A function that tries to insert if key doesn't already exist,
    // but if it does already exist, needs to get the current value
    void four(int id, const std::string &data)
    {
        std::pair<IdMap::iterator,bool> i =
            id_map.insert(IdMap::value_type(id, data));

        // Insertion worked, don't need to process old value
        if (i->second)
            return true;

        // Pass the id to some imaginary function that needs
        // to know id and wants to see the old string and new string
        report_conflict(id, i->first->second, data);
    }
};

Programmers often make multiple redundant calls to operator[]or call find, then redundant call operator[]or call find, then redundant call insert, out of laziness or ignorance. It is easy to use a card effectively if you understand its semantics.

0
source
Operator

[] actually returns the value & therefore, if you are sure that you want to insert an element, you can do something like:

map<Key, Value*> my_map;

Value& entry = my_map[key];  // insert occurs here, using default constructor.
if (entry == nullptr) entry = my_new_entry;  // just changing the value

The added benefit is that you only view once on a map.

0
source

All Articles