C ++ std :: vector записи имеют нулевое значение в функции, но размер остается больше нуля - PullRequest
0 голосов
/ 06 июня 2019

Уже давно я писал код на C / C ++, и я уже нашел альтернативное решение моей проблемы, но я хотел бы знать, почему оригинальный код не работает.

У меня есть тестовый класс, который в основном хранит только строку.

class test {
private:
        std::string name;
public:
        test(std::string name) : name(name) {};
        std::string get_name() { return name; }
};

В main У меня есть вектор, который я в одной точке заполняю test объектами. Код ниже имитирует нерегулярное использование вектора vect.

int main(void) {
        std::vector<test *> vect;
        std::vector<test *>::iterator i;

        //* Comment this for a working example
        std::cout << "Searching empty vector" << std::endl;
        i = *(_is_in_vector(vect, std::string("test 3")));
        if (i == vect.end()) {
                std::cout << "Nothing found" << std::endl;
        } // */

        vect.push_back(new test("test 1"));
        vect.push_back(new test("test 2"));
        vect.push_back(new test("test 3"));

        std::cout << "All:" << std::endl;
        i = *(_is_in_vector(vect, std::string("test 3")));
        if (i != vect.end()) {
                std::cout << "Erase " << (*i)->get_name() << std::endl;
                vect.erase(i);
                delete *i;
        }

        i = *(_is_in_vector(vect, std::string("test 3")));
        if (i == vect.end()) {
                std::cout << "Nothing found" << std::endl;
        }

        std::cout << "Left:" << std::endl;
        for (i = vect.begin(); i!=vect.end(); ++i) {
                std::cout << (*i)->get_name() << std::endl;
                delete *i;
        }

        vect.clear();
        return 0;
}

Поскольку поиск в векторе объекта test происходит несколько раз, я создал функцию _is_in_vector, которая ищет объект test и возвращает ему итератор.

static std::vector<test *>::iterator * _is_in_vector(std::vector<test *> &vect, std::string find) {
        std::string identity = find;
        static std::vector<test *>::iterator i = vect.begin();
        std::cout << "Vect size: " << vect.size() << std::endl;
        for (i; i != vect.end(); ++i) {
                std::string tmp = (*i)->get_name(); /* Segmentation fault after filling vector*/
                if (0 == identity.compare(tmp)) break;
        }
        return &i;
}

Проблема в том, что приведенный выше код работает, когда я закомментирую часть Searching empty vector в main. Когда вектор заполнен test объектами, я вызываю _is_in_vector во второй раз. Вектор в этой функции имеет три записи, но (*i) все указывают на NULL.

Выход:

Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Segmentation fault

Ожидаемый результат:

Searching empty vector
Vect size: 0
Nothing found
All:
Vect size: 3
Erase test 3
Vect size: 2
Nothing found
Left:
test 1
test 2

1 Ответ

5 голосов
/ 06 июня 2019

Прежде всего непонятно, почему вам нужно хранить test объекты по указателю, а не по значению.Если вам это нужно, используйте умный указатель.

Что касается вашей проблемы, почему вы возвращаете указатель на итератор?Это коренная причина вашей проблемы - чтобы сделать &i законным, чтобы вернуть вам, вы сделали это static, но static локальные переменные инициализируются только один раз и не меняют значения между вызовами - поэтому после первого вызова он указывает на элементв векторе, но после этого вы добавили элементы и сделали недействительными все итераторы, включая статические i, что означает ошибку сегментации.Так что исправить это просто - вернуть итератор по значению и сделать i не статичным, но регулярным, это легко и совершенно нормально.

PS Идентификаторы, начинающиеся с _, недопустимы в глобальном контексте,подробности можно найти здесь Каковы правила использования подчеркивания в идентификаторе C ++?

Итак, ваша функция должна выглядеть следующим образом:

static std::vector<test *>::iterator  is_in_vector( std::vector<test *> &vect, const std::string &find) 
{
      return std::find_if( vect.begin(), vect.end(), [find]( test *p ) {
          return p->get_name() == find;
      } );
}

при условии, чтовектор никогда не должен содержать nullptr, если дело обстоит так, или если вы играете безопасно, измените условие на:

          return p && p->get_name() == find;
...