std::sort 对包含 Objects* 指针的 Objects 向量进行排序
Posted
技术标签:
【中文标题】std::sort 对包含 Objects* 指针的 Objects 向量进行排序【英文标题】:std::sort on a vector of Objects containing Objects* pointers 【发布时间】:2015-04-07 21:38:05 【问题描述】:假设我定义了以下结构:
struct dockPose
Complex* pose;
int Cluster;
struct dockPose* DP;
float Distance;
int Density;
;
typedef struct dockPose DockPose;
然后,我声明一个向量,该向量将使用 std::sort() 函数按密度值排序。在调用 std::sort 之后,我的 DockPose* DP 指针是否仍指向它之前指向的同一个 DockPose 实例?如果没有,我该怎么做才能确保 DP 指针指向它在排序之前指向的相同 DockPose(如果有什么我可以做的)?
【问题讨论】:
指针是否指向您正在排序的向量中的其他对象?typedef struct foo Foo
用于旧版 C 兼容性;没有理由在新的 C++ 代码中使用它。
本杰明:是的。
感谢艾伦提供的信息。我大部分时间都习惯用 C 编写代码。
【参考方案1】:
是的,指针仍将指向同一个实例。但这可能不是你真正想要的。当您在向量上调用 std::sort
时,它不会更改实例的位置(这甚至不是您在 C++ 中可以做的事情)。它相互交换它们的值。用一个简化的例子可能会更好地解释这一点。采用这个结构:
struct Foo
int x;
Foo* buddy;
;
bool operator<(Foo const& lhs, Foo const& rhs)
return lhs.x < rhs.x;
现在,假设我制作了一个向量,其中 x 值递减,每个向量都有一个指向后面的指针(最后一个指针指向第一个):
std::vector<Foo> vec(5);
for (int i = 0; i < 5; ++i)
vec[i].x = 4 - i;
vec[i].buddy = &vec[(i + 1) % 5];
现在,如果我对这个向量进行排序,它基本上会反转。但是实例本身不会改变它们的位置。相反,它们的值会发生变化,使得第一个具有最低的x
值,并从那里增加。现在,指针成员随着x
值的变化而变化。
以vec[0]
为例,它的x
值为4,还有一个指向vec[1]
的指针(x
的值为3)。排序后,这些值将出现在最后一个元素 vec[4]
中。所以vec[4]
将有一个x
的值为4,以及一个指向vec[1]
的指针(在排序之后,它的x
的值为1)。
因此,在排序之前,x
值为 4 的元素有一个指向 x
值为 3 的元素的指针。排序之后,x
值为 4 的元素有一个指向 x
值为 1 的元素的指针。我怀疑这是你想要的。
由于您对实例的身份感兴趣,而不仅仅是它们的值,您可能应该使用std::vector<std::unique_ptr<dockPose>>
之类的东西。对于我的Foo
示例,我可以这样做:
std::vector<std::unique_ptr<Foo>> vec;
for (int i = 0; i < 5; ++i)
vec.emplace_back(new Foo);
for (int i = 0; i < 5; ++i)
vec[i]->x = 4 - i;
vec[i]->buddy = vec[(i + 1) % 5].get();
请注意,执行此操作时,您需要使用不同的比较函数。一种比较取消引用的指针,而不是指针本身。
【讨论】:
我真的很喜欢你的建议,它解释了我之前在测试时看到的内容。我将在今晚晚些时候实施和测试它。感谢您的回答质量(如果可以的话,我会投票)。 为什么不使用单独的指针向量来指向 dockPose 结构?然后根据 dockPose 结构对指针向量进行排序。指针向量和 dockPose 结构体需要是同一类的成员。然后,您可以将函数运算符 (functor) 或 lambda 函数用于 std::sort() 使用的比较函数。 ...或者你想实现某种类型的链表?【参考方案2】:std::sort
只会在向量中移动对象,但指针本身仍将指向它们最初指向的相同内存位置。
【讨论】:
除了不同的东西会在这些内存位置【参考方案3】:排序不会改变这些指针的值。指针只是保存内存地址的变量,对向量进行排序不会改变向量中对象的任何成员变量数据。
【讨论】:
排序不会改变指针的值,但是你正在移动你指向的东西,所以在排序之后指针仍然指向相同的内存位置,但可能有该位置的另一个对象。【参考方案4】:如果你有一个DockPose
对象的向量,你将它们视为值,在这种情况下,保留指向它们的指针是个坏主意。我怀疑您实际上希望它们成为实体(即使它们具有相同的值,两个实体也是不同的)。
在这种情况下,您应该使用指向实体的指针向量;对指针向量进行排序不会使您的 DP
指针无效。
【讨论】:
【参考方案5】:在向量中保留指向对象的指针不是一个好主意。如果您碰巧导致调整大小,即使是简单的 push_back() 也可能使您的所有指针无效。 如果要在容器中保留指向对象的指针,最好使用 std::list
【讨论】:
以上是关于std::sort 对包含 Objects* 指针的 Objects 向量进行排序的主要内容,如果未能解决你的问题,请参考以下文章
使用 std::sort 对包含两个数据成员的对象向量进行排序
C++ - 使用 std::sort 对结构向量进行排序导致读取访问冲突