1

考虑以下程序。它创建一组指向整数的指针,并使用自定义的 indrect_less 比较器,该比较器根据指向的整数的值对集合进行排序。完成此操作后,我将更改指向整数之一的值。然后,可以看到集合的顺序不再排序(我想是因为集合不知道有什么改变了)。

(不要介意 C++0x 循环,我在 VS2010 上运行)

#include <iostream>
#include <set>
using namespace std;

struct indirect_less {
    bool operator()(int* l, int* r) const
    {
        return *l < *r;
    }
};

int main()
{
    set<int*, indirect_less> myset;

    int* a = new int(5);
    int* b = new int(6);
    int* c = new int(7);

    myset.insert(a);
    myset.insert(b);
    myset.insert(c);

    cout << "Set contains: ";
    // (outputs: 5 6 7)

    for (auto i = myset.begin(), end = myset.end(); i != end; ++i)
    {
        cout << **i << " ";
    }

    cout << endl << "Modifying *a" << endl;
    *a = 9;         // point of interest
    cout << "Set contains: ";
    // (outputs: 9 6 7 - unsorted order)

    for (auto i = myset.begin(), end = myset.end(); i != end; ++i)
    {
        cout << **i << " ";
    }

    cout << endl;

    cin.get();

    return 0;
}

1)我在调用未定义的行为是对的吗?行后整个状态是否myset无效*a = 9;

2)这样做是擦除然后重新插入的唯一正确方法a吗?

3)有什么方法,一旦*a = 9;运行,重新平衡集合到排序顺序,具有明确定义的行为?

4

3 回答 3

2

是的,std::set假设元素是不可变的。如果有危险,可以在每次更改后自行重新排序。不过,我不推荐它:使用其他集合类型。

于 2010-08-10T16:50:14.220 回答
1

1) 是的,set 不允许修改它的元素。

2)除了删除旧值并插入新值外,您还可以将旧集合替换为新构建的集合。

3) 没有

于 2010-08-10T16:54:25.533 回答
1

1)我不知道行为是未定义的。这个例子中的另一个转折是集合的元素没有改变——集合的每个元素都是一个指针。如果你在执行'*a = 9'行之前和之后打印出集合的(指针)元素,我相信你会发现指针值在赋值之前和之后的顺序相同。改变的是一个集合元素指向的值。这发生在集合的主持之外,因此集合无法维持您想要的顺序。

2) 一个合格的“是”。这将强制使用indirect_less() 来对集合中的元素进行排序。同样,请注意,您正在按每个取消引用指针的值对集合中的元素(指针)进行排序。然而,这让我觉得有点冒险,正如你所描述的那样。

从打印输出中的图例“Set contains:”中,我推测此示例努力形成一组整数。然而,定义的集合,即“集合”实际上由指向整数的指针组成,而不是整数本身。我相信期望和实际集合之间的这种错位是问题的根本原因。

3) 见 2)。

于 2010-08-10T17:33:42.290 回答