【问题标题】:Can a QPointer be the key to a std::mapQPointer 可以成为 std::map 的关键吗
【发布时间】:2011-03-08 21:17:40
【问题描述】:

根据SGI's doc on associative containers,“由于元素是根据它们的键存储的,因此与每个元素关联的键是不可变的”。我有时使用指针作为 std::map 的键,因为虽然指向的对象可能是可变的,但指针本身是常量。

QPointer 在技术上是一个模仿指针的对象,Qt's doc 说我们可以像使用指针一样使用 QPointer。由于 QPointer 对象本身在执行过程中可能会发生变化,那么它仍然可以用作 std::map 容器的键吗?

编辑 1:我不能使用 QMap,我必须坚持使用 std::map。
编辑 2:当我使用 QPointer 时代码编译。问题是我是否应该在运行时期待不愉快的意外。

【问题讨论】:

标签: c++ qt stl qpointer


【解决方案1】:

不,这是不安全的,因为当 QObject 被销毁时,QPointer<T> 可能会更改为 NULL。 (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!

【讨论】:

    【解决方案2】:

    我认为(从最不意外的原则)QPointer 不会“神奇地”改变它指向的位置,如果你不重新分配它并且不删除底层对象,所以它应该是安全的.

    (我必须补充一点,我已经多次看到 Qt 违反了最小意外原则,因此请务必进行测试。)

    【讨论】:

      【解决方案3】:

      比较来自不同分配块的指针以获取除相等/不相等之外的任何内容是未定义的行为。 IE。使用 new 或 malloc 分配块后,您可以遍历缓冲区并测试您的指针是否小于缓冲区的末尾。但是你不能做两个单独的新闻/mallocs 并比较结果指针以获取除相等/不等之外的任何内容。

      嗯...你可以,但你可能不喜欢结果。

      【讨论】:

      • 但是关联容器使用std::less,它被定义为适用于任何指针类型。
      • 也许我使用的文档已经过时了。我正在查看标准部分的行,该部分表示指针之间的关系运算符给出未指定的行为,除非它们指向同一分配。这不再是真的吗?
      • 关联容器不使用关系运算符,它们使用std::less。这是专门定义的,以给出指针的总排序,即使关系运算符没有。
      • 感谢您的澄清。一直以来,我一直在研究 5.9 并将该规则应用于地图。这是您学到一些东西的好日子。
      猜你喜欢
      • 1970-01-01
      • 2021-02-24
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 2015-08-11
      相关资源
      最近更新 更多