首页 > 解决方案 > list::iterator 对移至列表无效?

问题描述

我已经使用了相当数量的 C++,但没有那么多std::list.. 在我当前的项目中,我需要一个std::list<..>数据成员,并使用std::list<..>::iterator. 该对象也必须是可移动的,但在我的情况下,默认的移动构造函数是不可能的。这里std::list做了一些让我吃惊的事情。

考虑

#include <list>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

template<typename T>
void test() {
    T l { 1, 2, 3, 4, 5 };
    cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
    auto pos = find(l.begin(), l.end(), 6);
    if (pos == l.end()) cout << "l end\n";

    cout << "---- moving l > lmv ----" << endl;
    T lmv { std::move(l) };
    cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
    cout << "lmv = "; for(const auto& e: lmv) cout << e << " "; cout << endl;
    if (pos == l.end()) cout << "l end\n";
    if (pos == lmv.end()) cout << "lmv end\n";
}

int main() {
    cout << "___vector___\n";
    test<vector<int>>();
    cout << "___list___\n";
    test<list<int>>();
}

这输出

___vector___
l = 1 2 3 4 5 
l end
---- moving l > lmv ----
l = 
lmv = 1 2 3 4 5 
lmv end
___list___
l = 1 2 3 4 5 
l end
---- moving l > lmv ----
l = 
lmv = 1 2 3 4 5 
l end

即指向被移动的lists 端的迭代器不指向被移动的lists 端。但vector如果迭代器本质上是指针,它确实适用于,这是我一直期望的。为什么不list一样?元素的内存位置不应该随着移动而改变..list移动是否改变列表迭代器?为什么?

我在 Windows 10 的 MSYS2 下使用“g++.exe(Rev1,由 MSYS2 项目构建)10.2.0”

标签: c++listiteratormove-semantics

解决方案


移动容器时应保留迭代器。

然而end,容器的迭代器不指向元素,因此在移动容器时允许无效

如果您更改您的代码以使用begin而不是end那么它会按您预期的那样工作。

#include <list>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

template<typename T>
void test() {
    T l { 1, 2, 3, 4, 5 };
    cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
    auto pos = find(l.begin(), l.end(), 1);
    if (pos == l.begin()) cout << "l begin\n";

    cout << "---- moving l > lmv ----" << endl;
    T lmv { std::move(l) };
    cout << "l = "; for(const auto& e: l) cout << e << " "; cout << endl;
    cout << "lmv = "; for(const auto& e: lmv) cout << e << " "; cout << endl;
    if (pos == l.begin()) cout << "l begin\n";
    if (pos == lmv.begin()) cout << "lmv begin\n";
}

int main() {
    cout << "___vector___\n";
    test<vector<int>>();
    cout << "___list___\n";
    test<list<int>>();
}

请注意,比较来自两个不同容器的迭代器是未定义的行为,因此最终pos == l.begin()是未定义的行为,并且 Visual Studio 的调试版本至少会在运行此代码时抛出断言。

我想您的原始代码可以工作,因为std::vector end迭代器通常只是实现为指向最后一个元素之后的一个。我会想象std::list结束迭代器包含一个空指针和一个指向列表的指针。


推荐阅读