Может ли QPointer быть ключом к std :: map - PullRequest
4 голосов
/ 09 марта 2011

Согласно Документу SGI по ассоциативным контейнерам , "поскольку элементы хранятся в соответствии с их ключами, важно, чтобы ключ, связанный с каждым элементом, был неизменным".Иногда я использую указатель в качестве ключа для std :: map, поскольку, хотя указанный объект может быть изменяемым, сам указатель является константой.

Технически QPointer - это объект, имитирующий указатель, а Qt'sdoc говорит, что мы можем использовать QPointers точно так же, как указатели.Поскольку сам объект QPointer может измениться во время выполнения, может ли он по-прежнему использоваться в качестве ключа для контейнера std :: map?

Редактировать 1: я не могу использовать QMap, я должен придерживаться std:: map.
Edit 2: код компилируется, когда я использую QPointer.Вопрос в том, стоит ли ожидать неприятных сюрпризов во время выполнения.

Ответы [ 3 ]

6 голосов
/ 09 марта 2011

Нет, это небезопасно, поскольку QPointer<T> может измениться на NULL при уничтожении QObject.(QPointer похоже на std::weak_ptr.) Таким образом, этот код будет производить неопределенное поведение:

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!
0 голосов
/ 09 марта 2011

Неопределенное поведение сравнивать указатели из разных блоков выделения для чего-либо, кроме равенства / неравенства. То есть После выделения блока с помощью new или malloc вы можете пройти через буфер и проверить, меньше ли ваш указатель, чем конец буфера. Но вы не можете сделать две отдельные новости / malloc и сравнить полученные указатели для чего-либо, кроме равенства / неравенства.

Ну ... вы можете, но вам могут не понравиться результаты.

0 голосов
/ 09 марта 2011

Я понимаю (из принципа наименьшего удивления), что QPointer не "волшебным образом" изменит свое местоположение, если вы не переназначаете его и не удаляете базовый объект, поэтому он должен быть безопасным.

(Должен добавить, что я видел, как Qt несколько раз нарушал принцип наименьшего удивления, так что проверяйте, чтобы быть уверенным.)

...