c++qtstlqpointer

Can a QPointer be the key to a std::map


According to SGI's doc on associative containers, "Since elements are stored according to their keys, it is essential that the key associated with each element is immutable". I sometimes use a pointer as a key to std::map, since, although the pointed object might be mutable, the pointer itself is constant.

QPointer is technically an object mimicking a pointer, and Qt's doc says that we can use QPointers exactly like pointers. Since the QPointer object itself may change during execution, can it still be used as the key to a std::map container?

Edit 1 : I can't use a QMap, I have to stick to std::map.
Edit 2 : The code compiles when I use a QPointer. The question is about whether I should expect unpleasant surprises at runtime.


Solution

  • No, this is not safe, because QPointer<T> may change to NULL when a QObject is destroyed. (QPointer is similar to std::weak_ptr.) So this code would produce Undefined Behavior:

    class CopyableWidget : public QWidget {
      Q_OBJECT;
    public:
      CopyableWidget(Widget* parent = 0) : QWidget(parent) {}
      CopyableWidget(const CopyableWidget& w, Widget* parent = 0) : QWidget(parent) {}
    };
    
    std::vector<CopyableWidget> v(2); // Two default-constructed widgets
    std::map<QPointer<CopyableWidget>, int> wid_values;
    wid_values[&v[0]] = 1;
    wid_values[&v[1]] = 2;
    // wid_values contains { {&v[0], 1}, {&v[1], 2} }
    v.resize(1);
    // The QPointer in wid_values constructed from &v[1] now acts like NULL.
    // wid_values contains { {&v[0], 1}, {NULL, 2} }
    // But &v[0] > NULL (on most platforms). Class invariant was violated!