【问题标题】:std::unique with class objectsstd::unique 与类对象
【发布时间】:2017-03-28 09:24:59
【问题描述】:

有一个带有指向类对象的指针的双端队列:

deque<myClass*> mydeque;

假设我们在双端队列中有 3 个对象:obj1, obj2, obj3

根据一些比较逻辑说obj1obj2 被认为是相同的元素。

当我们在 mydeque 上调用 std::unique 时,它会将双端队列更改为如下所示:

obj1 obj3 obj3

这是因为根据 std::unique 的文档 删除是通过用下一个不重复的元素替换重复的元素来完成的

std::unique 返回一个指向最后一个 obj3 的迭代器。 如果我们想释放obj2占用的内存空间(通过调用delete),如何实现呢?

这里我们不能在返回的迭代器上调用 delete,因为它实际上会删除 obj3。

【问题讨论】:

  • 不要使用原始指针;使用std::shared_ptr&lt;myClass&gt; 并让理智解决它。
  • obj3 发生了什么事?您是否将原始 newed 指针存储在向量中?
  • 如果你有deque的指针,那么std::unique应该处理不同地址的对象,那么你的问题是什么?
  • 我已经编辑了这个问题以更好地解释它
  • @WhozCraig 或者,更好的是:std::unique_ptr

标签: c++ stl deque


【解决方案1】:

std::unique 的文档是这样说的:

删除是通过移动范围内的元素以覆盖要删除的元素来完成的。 保留元素的相对顺序,容器的物理大小不变。

指向范围的新逻辑端和物理端之间的元素的迭代器仍然是可解引用的,但元素本身具有未指定的值。

调用 unique 之后通常会调用容器的 erase 方法,该方法会删除未指定的值并减小容器的物理大小以匹配它的新逻辑大小。

注意 2 个粗体部分。第一个很重要,它表示保留了相对顺序,即在调用std::unique 之后,您的双端队列仍将包含

obj1 obj2 obj3

他们的顺序没有改变,为什么?因为非唯一元素已经在末尾了,obj3,并且因为顺序被保留了,你可以确定它仍然在末尾。

您已经知道第二个粗体部分,但现在您知道 std::unique 返回一个迭代器到最后一个有效元素之后,您可以调用 std::deque::erase 来擦除每个非唯一元素:

mydeque.erase(std::unique(mydeque.begin(), mydeque.end()), mydeque.end());

还请注意,因为您要存储指针,所以拥有 2 个相同元素的唯一方法是让 2 个指针指向相同的地址。

【讨论】:

  • 正确。我的错,我举错了例子。我已经改正了
  • @bishwanathmandal std::unique 不会替换任何东西,它只是将它们移到最后。
  • 根据 std::unique 的文档删除是通过用下一个不重复的元素替换重复的元素来完成的
  • ** 该函数无法更改包含元素范围的对象的属性(即,它无法更改数组或容器的大小):删除是通过将重复元素替换为下一个不重复的元素,并通过将迭代器返回到应该被视为其新的过去元素的元素来指示缩短范围的新大小。**
  • @bishwanathmandal cplusplus 是一个过时的参考,而且大部分时间都是错误的,就像这次一样。您应该改用 cppreference,它指出“通过移动范围内的元素来完成删除,从而覆盖要擦除的元素”
【解决方案2】:

使用 C++11 功能。使用 std::unique_ptr 而不是原始指针。这样,当指向obj3 的指针被覆盖时,其目标将被删除。

如果此mydeque 结构不是myClass 对象的所有者,则改用std::shared_ptr

第三种选择是循环排序的双端队列并自己删除重复值。它必须已经排序,因为std::unique 仅适用于排序间隔。

【讨论】:

  • @Rakete1111:谢谢。固定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
相关资源
最近更新 更多