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&lt;std::unique_ptr&lt;dockPose&gt;&gt; 之类的东西。对于我的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 对包含两个数据成员的对象向量进行排序

类指针向量上的std :: sort()

使用 std::sort 对对象向量进行排序

C++ - 使用 std::sort 对结构向量进行排序导致读取访问冲突

如何使用单独类的属性对向量进行 std::sort [关闭]

使用 std::sort() 对对象向量进行排序