Kevin Yin
Kevin Yin

Reputation: 882

Order of destruction in unordered_map

I have an unordered_map of objects. Each object, in its destructor, browses the unordered map to find other objects, and then tweaks these other objects. This will fail if the other objects are zombie objects, but if the other objects are entirely removed from the unordered_map, there is no problem.

My questions:

  1. does this work if I erase() an object, and its destructor tries to look for itself in the unordered map? Specifically, is the destructor called first, or is the object removed from the unordered_map first, or is there no guarantee?
  2. does this work if the unordered_map is destroyed? Specifically, will the unordered_map be in a valid state as each individual destructor is called?

Upvotes: 2

Views: 1602

Answers (2)

Gaba Miau
Gaba Miau

Reputation: 38

I think i found a decent solution. You could possibly encapsulate an unordered_map in a class and use its distructor to raise a flag and detect it as an edge case in the destructor of the object that is typaram in the hash table. Like this:

template<typename K, typename V>
struct hash_table
{
    unordered_map<K, V> map;
    bool is_being_deleted = false;
    ~hash_table()
    {
        is_being_deleted = true;
    }
};

struct PageRefrence
{
    string str;
    int page;
    hash_table<string, PageRefrence>& refTable;
    ~PageRefrence()
    {
        if (refTable.is_being_deleted == true) // When the map is in the procces of deletion
            return;
        else
        { // Normal case
            auto x = refTable.map.find(str);
            cout << (*x).second.page;
        }

    }
};

int main()
{
    hash_table<string, PageRefrence> refTable;
    refTable.map.insert({ "HELP",{"HELP",42,refTable} });
}

Upvotes: 0

Daniel Jour
Daniel Jour

Reputation: 16156

The lifetime of an object of type T ends when [...] if T is a class type with a non-trivial destructor (12.4), the destructor call starts [...]

[§ 3.8/1 N4431]

And, further down

The properties ascribed to objects throughout this International Standard apply for a given object only during its lifetime

[§ 3.8/3 N4431]

And finally

[...] after the lifetime of an object has ended [...] any pointer that refers to the storage location where the object will be or was located may be used but only in limited ways. [...] The program has undefined behavior if [...] the pointer is used to access a non-static data member or call a non-static member function of the object [...]

[§ 3.8/5 N4431]

So, since you must have some kind of reference (e.g. a pointer, or a real reference, which I'd count as pointer here, too) to the map, and its lifetime has ended, accessing a member function (to get an iterator for example) will - as far as I'd read this part of the standard - lead to undefined behaviour.

I was also looking at the part of the standard about unordered containers and containers in general, and couldn't find an exception to the above or any clue about the state during destruction.

So: Don't do this. Neither with unordered containers, nor with any other object.


BTW: What kind of tweaking makes any sense when you do it on objects that will be destructed moments thereafter?

Upvotes: 3

Related Questions