1

根据 SGI、cplusplus.com 和我拥有的所有其他来源,std::list 的 sort() 成员函数不应使迭代器无效。但是,当我运行此代码(c++11)时,情况似乎并非如此:

#include <list>
#include <chrono>
#include <random>
#include <iostream>
#include "print.hpp"
unsigned int seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator(seed);
std::uniform_int_distribution<unsigned int> distribution(1, 1000000000);
auto rng = std::bind(distribution, generator);
// C++11 RNG stuff. Basically, rng() now gives some unsigned int [1, 1000000000]

int main() {
    unsigned int values(0);
    std::cin >> values;           // Determine the size of the list
    std::list<unsigned int> c;
    for (unsigned int n(0); n < values; ++n) {
        c.push_front(rng());
    }
    auto c0(c);
    auto it(c.begin()), it0(c0.begin());
    for (unsigned int n(0); n < 7; ++n) {
        ++it;     // Offset these iterators so I can print 7 values
        ++it0;
    }
    std::cout << "With seed: " << seed << "\n";
    std::cout << "Unsorted list: \n";
    print(c.begin(), c.end()) << "\n";
    print(c.begin(), it) << "\n\n";
    auto t0 = std::chrono::steady_clock::now();
    c0.sort();
    auto d0 = std::chrono::steady_clock::now() - t0;
    std::cout << "Sorted list: \n";
    print(c0.begin(), c0.end()) << "\n";
    print(c0.begin(), it0) << "\n";  // My own print function, given further below
    std::cout << "Seconds: " << std::chrono::duration<double>(d0).count() << std::endl;
    return 0;
}

在 print.hpp 中:

#include <iostream>

template<class InputIterator>
std::ostream& print(InputIterator begin, const InputIterator& end, 
                    std::ostream& out = std::cout) {
    bool first(true);
    out << "{";
    for (; begin != end; ++begin) {
        if (first) {
            out << (*begin);
            first = false;
        } else {
            out << ", " << (*begin);
        }
    }
    out << "}";
    return out;
}

样本输入/输出:

11
With seed: 3454921017
Unsorted list: 
{625860546, 672762972, 319409064, 8707580, 317964049, 762505303, 756270868, 249266563, 224065083, 843444019, 523600743}
{625860546, 672762972, 319409064, 8707580, 317964049, 762505303, 756270868}

Sorted list: 
{8707580, 224065083, 249266563, 317964049, 319409064, 523600743, 625860546, 672762972, 756270868, 762505303, 843444019}
{8707580, 224065083}
Seconds: 2.7e-05

一切都按预期工作,除了打印。它应该显示 7 个元素,但实际数字相当随意,前提是“值”设置为大于 7。有时它不给出,有时给出 1,有时给出 10,有时给出 7,等等。所以,有没有我的代码明显有问题,或者这是否表明 g++ 的 std::list (和 std::forward_list )不符合标准?

提前致谢!

4

1 回答 1

11

迭代器仍然有效,并且仍然引用列表中的相同元素,这些元素已重新排序

所以我不认为你的代码做你认为它做的事情。它从头开始打印列表,直到列表排序后第 7 个元素结束。因此,它打印的元素数量当然取决于列表中的值。

考虑以下代码:

#include <list>
#include <iostream>

int main() {
    std::list<int> l;
    l.push_back(1);
    l.push_back(0);
    std::cout << (void*)(&*l.begin()) << "\n";
    l.sort();
    std::cout << (void*)(&*l.begin()) << "\n";
}

打印的两个地址不同,表明(与 不同std::sortstd::list::sort通过更改元素之间的链接进行排序,而不是通过为元素分配新值。

我一直认为这是强制性的(同样适用于reverse())。我实际上找不到明确的文字可以这么说,但是如果您查看 的描述merge,并认为list::sort存在的原因可能是因为 mergesort 可以很好地与列表一起使用,那么我认为它“显然”是有意的。merge说,“指向 x 的移动元素的指针和引用现在引用那些相同的元素,但作为 *this 的成员”(23.3.5.5./23),并且包含mergesort说的部分的开头,“因为列表允许快速从列表中间插入和擦除,某些操作是专门为它们提供的”(23.3.5.5/1)。

于 2012-11-12T17:10:26.843 回答