迭代器在添加到添加到列表向量的结构中时会停止指向某个值吗?

问题描述 投票:-2回答:2

我正在做的项目的前提是使用迭代器而不是指针来制作跳过列表。我创建了一个节点列表向量。在节点结构中,它包含一个迭代器,它应该是保留位置的下面列表的迭代器。问题是当我创建一个新节点时,将其下面的迭代器设置为下面的迭代器列表,然后尝试通过引用它来访问它,它会出现故障。我认为这是因为迭代器没有被初始化并且它不能被解除引用,因为它似乎不是一个边界问题。


struct Node // in header file
{
  int value;
  list<Node>::iterator below;
   Node(int v, list<Node>::iterator b){
        value = v;
        below = b;
   }
   Node(){} 
   Node(int v){
        value = v;
   }


};


vector<list<Node>> skipList; //this is the skipList initialized in the header

//插入调用以将数字添加到跳过列表

void SkipLists::insert(int num){
    list<Node>::iterator loc;
    if(skipList.empty()){
        list<Node> nodes;
        nodes.push_back(Node(num));
        skipList.push_back(nodes);
    }else{
        loc = insertPlace(num, skipList[skipList.size()-1].begin(), skipList.size() -1);
        skipList[0].insert(loc, Node(num));

    }
    cout << "1.  " << *this << "\n\n\n";
    stack(num, loc);

    //this if statement also segfaults
    if(skipList.size() > 1){
        cout << (*(skipList[1].front().below)).value;
    }

}

//在insertPlace函数中,只有在进行递归调用时,它才会在while循环上进行segfaults。意味着添加到skiplist的先前值具有高度。解除引用它时会出现段错误。我通过将它移出while循环来测试它。

list<Node>::iterator SkipLists::insertPlace(int num, list<Node>::iterator it, int height){
    if(height == 0){
        while(it != skipList[0].end() && skipList[0].size() > 0 && num > (*it).value){            // problem: likely not returning a good (*it).below or never setting it properly. 
            it++;
        }
        return it;
    }
    while(it != skipList[height].end() && skipList[height].size() > 0 && num > (*it).value){
        cout << "he\n";
        it++;
        cout << "lo\n";
    }
    return insertPlace(num, (*it).below, --height);
}

stack用于根据概率在跳过列表中添加垂直元素。这是节点被赋予“下面”迭代器的地方。


void SkipLists::stack(int num, list<Node>::iterator loc){
    int flip = rand() % 2;
    int count = 1;
    list<Node>::iterator prev = loc;
    list<Node>::iterator it;
    while(flip == 1){
        count++;
        flip = rand() % 2;

        if(skipList.size() < count){
            list<Node> nodes;
            nodes.push_back(Node(num, prev));
            skipList.push_back(nodes);
            prev = skipList[skipList.size()-1].begin();
        }else{
            it = skipList[count-1].begin();
            while(it != skipList[count -1].end() && num > (*it).value){
                it++;
            }
            prev = skipList[count -1].insert(it,Node(num, prev));

        }
    }
}

c++ list stl iterator
2个回答
0
投票

vector<list<Node>> skipList;很危险。如果添加了新列表,则向量可能会重定位所有其他列表,并使所有存储的迭代器无效。即使列表可以在新位置移动构造,它们仍然是新对象,并且将.end()与从另一个对象获得的迭代器进行比较是未定义的行为。

我认为这是你的代码最终会发生的事情。

[可能不是一个正确的答案,但它的评论太长了,我不会调试作者的代码来确保。]


0
投票

一个明显的错误是你的Node类实现。

如果你看看你的Node构造函数只需要一个int,你就无法初始化below迭代器。因此,尝试取消引用below时的任何访问都将导致发生未定义的行为,正如您在此行中所做的那样:

cout << (*(skipList[1].front().below)).value;

如果跳过列表为空,您将看到您的代码将生成Node对象,其中below未初始化。

以下是使用或多或少使用您发布的代码的简单示例:

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

struct Node // in header file
{
    int value;
    std::list<Node>::iterator below;
    Node(int v, std::list<Node>::iterator b) {
        value = v;
        below = b;
    }
    Node() {}
    Node(int v) {
        value = v;
    }
};

class SkipLists
{
    private:
        std::vector<std::list<Node>> skipList;
    public:
        void insert(int num);
        std::list<Node>::iterator insertPlace(int num, std::list<Node>::iterator it, int height);
        void stack(int num, std::list<Node>::iterator loc);
};

using namespace std;

void SkipLists::insert(int num) 
{
    list<Node>::iterator loc;
    if (skipList.empty()) 
    {
        list<Node> nodes;
        nodes.push_back(Node(num));
        skipList.push_back(nodes);
    }
    else 
    {
        loc = insertPlace(num, skipList[skipList.size() - 1].begin(), skipList.size() - 1);
        skipList[0].insert(loc, Node(num));

    }

    stack(num, loc);

    //this if statement also segfaults
    if (skipList.size() > 1) {
        cout << (*(skipList[1].front().below)).value;
    }
}

list<Node>::iterator SkipLists::insertPlace(int num, list<Node>::iterator it, int height) 
{
    if (height == 0) {
        while (it != skipList[0].end() && skipList[0].size() > 0 && num > (*it).value) 
        {
            it++;
        }
        return it;
    }
    while (it != skipList[height].end() && skipList[height].size() > 0 && num > (*it).value) 
    {
        cout << "he\n";
        it++;
        cout << "lo\n";
    }
    return insertPlace(num, (*it).below, --height);
}

void SkipLists::stack(int num, list<Node>::iterator loc) {
    int flip = rand() % 2;
    int count = 1;
    list<Node>::iterator prev = loc;
    list<Node>::iterator it;
    while (flip == 1) {
        count++;
        flip = rand() % 2;

        if (skipList.size() < count) {
            list<Node> nodes;
            nodes.push_back(Node(num, prev));
            skipList.push_back(nodes);
            prev = skipList[skipList.size() - 1].begin();
        }
        else {
            it = skipList[count - 1].begin();
            while (it != skipList[count - 1].end() && num > (*it).value) {
                it++;
            }
            prev = skipList[count - 1].insert(it, Node(num, prev));
        }
    }
}

// Test    
int main()
{
    SkipLists s;
    s.insert(4);
}

您将看到below未在您运行此非常小的样本时说明您的应用程序崩溃的行上初始化。

Node默认构造函数也存在同样的问题,其中valuebelow成员都未初始化。创建对象时,所有成员都应处于某种有效状态,或者以某种方式为“null”。对于迭代器,由于没有“null”迭代器,因此更难执行此操作,除非您可以将迭代器设置为现有列表的end()迭代器。

基本上你需要设计你的类,以便你确定迭代器指向某个有效的地方,或者指示迭代器不应该被解引用的其他方法。

© www.soinside.com 2019 - 2024. All rights reserved.