Указатель на объект в векторе иногда указывает на другой объект в векторе - PullRequest
1 голос
/ 08 марта 2020

В приведенном ниже коде указатель Struct1 в Struct2 должен последовательно указывать на определенный объект Struct1. Каждая из этих структур содержится в векторе.

Однако при выводе индексной переменной объектов Struct1, указанных в объектах Struct2, в некоторых случаях возвращается неправильный.

Почему указатель на объект, содержащийся в векторе, иногда указывает на другой объект в векторе?

struct Struct1
{
    size_t index;
    std::vector<size_t> data;
}

struct Struct2
{
    Struct1 *s1;
}

class MyClass
{
    std::vector<Struct1> s1s;
    std::vector<Struct2> s2s;
    size_t propIndex = 0;

    void input(QByteArray &line)
    {
        if (line == "1") {
            for (size_t i = s1s.size(); i <= propIndex; i++) {
                s1s.push_back({ .index = i, .data= {} });
            }
            QByteArrayList list = getList();
            for (auto id : list)  s1s.at(propIndex).data.push_back(id.toULongLong());
        }
        else {
            if (propIndex == s2s.size()) {
                s2s.push_back({ .s1 = nullptr });
            }

            if (line == "2") {
                size_t index = getIndex();
                for (size_t i = s1s.size(); i <= index; i++) {
                    s1s.push_back({ .index = i, .data= {} });
                }
                s2s.at(propIndex).s1 = &s1s.at(index);
            }
        }

        propIndex++;
    }

    QByteArrayList output()
    {
        QByteArrayList output;

        for (auto s2 : s2s) {
            output += QByteArray::number(s2.s1->index) + "\n";
        }

        return output;
    }
}

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Проблема в том, что вы берете указатель на элемент в векторе:

s2s.at(propIndex).s1 = &s1s.at(index);

Вектор является динамической c структурой, и его данные могут быть перераспределены, когда он растет. Таким образом, любой push_back() может сделать недействительными все указатели:

s1s.push_back({ .index = i, .data= {} });

Обратите внимание, что алгоритм распределения векторов предназначен для резервирования пространства для нескольких элементов, когда его необходимо увеличить. Это объясняет, что проблема появляется только время от времени.

Одним из решений может быть сохранение не указателя, а индекса элементов вместе с указателем на вектор.

0 голосов
/ 09 марта 2020

Как обсуждалось в комментариях к принятому ответу, возможное решение использует unique_ptr s.

В примере кода OPs вектор Struct1 будет заменен вектором unique_ptr:

    std::vector<std::unique_ptr<Struct1>> s1s;

Затем объекты должны быть выделены независимо, и необходимо создать уникальный указатель для сохранения в векторе, и нам нужно вызвать .get(), чтобы получить необработанный указатель на объект:

    if (line == "1") {
        for (size_t i = s1s.size(); i <= propIndex; i++) {
            s1s.push_back(std::unique_ptr<Struct1>(new Struct1({ .index = i, .data = {} })));
        }
        QByteArrayList list = getList();
        for (auto id : list)  s1s.at(propIndex)->data.push_back(id.toULongLong());
    }

...

            if (line == "2") {
            size_t index = getIndex();
            for (size_t i = s1s.size(); i <= index; i++) {
                s1s.push_back(std::unique_ptr<Struct1>(new Struct1({ .index = i, .data = {} })));
            }
            s2s.at(propIndex).s1 = s1s.at(index).get();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...