струны и магазин - PullRequest
       24

струны и магазин

2 голосов
/ 27 января 2011

В приведенной ниже программе строка добавляется в пустой магазин.Затем адрес этого элемента store сохраняется в указателе 's1'.Затем добавляется еще одна строка, и это как-то приводит к сбою указателя на исходный элемент.

Ответы [ 4 ]

3 голосов
/ 27 января 2011

Когда вы добавляете новый элемент в std::vector, вектору может потребоваться расширить свой буфер, и при этом он, вероятно, переместит буфер в другую область памяти. Таким образом указатели на его элемент становятся недействительными. Короче говоря, указатели на элементы вектора не гарантируются действительными после изменения размера вектора, и push_back может изменять размер вектора, если у него недостаточно зарезервированного пространства.

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

1 голос
/ 27 января 2011

Есть ли у вас особая причина, по которой вы хотите использовать указатели (куча)?Если нет, просто сделайте:

   class store2
    {
        public:
            void add(std::string s) {words.push_back(s);}
            std::string last_added() { if (words.size() == 0) return "";
return words[words.size()-1];}

        private:
            std::vector<std::string> words;
    }

;

1 голос
/ 27 января 2011

Если вам нужно убедиться, что указатели в коллекции остаются действительными, вы, вероятно, хотите что-то, кроме вектора (например, вы можете использовать std::deque или std::list вместо этого - с std::deque, как правило, предпочтительным между два).

В качестве альтернативы, вместо возврата указателя (как правило, плохая идея), вы можете вернуть индекс строки и предоставить функцию-член, которая индексирует вектор, когда он используется.

0 голосов
/ 27 января 2011
Итераторы

std::vector могут быть недействительными при изменении его содержимого. См. аннулирование векторного итератора .

Если вы действительно хотите сохранить существующий интерфейс и сохранить указатели от элементов, вставленных в ваш вектор, вы можете хранить строки по указателям, а не по значению, например:

#include <iostream>
#include <string>
#include <vector>
#include <memory>

class store2
{
public:
    store2 ()
    {
    }

    ~store2 ()
    {
        for (std::vector<std::string *>::iterator it =
                 words.begin (), end_it = words.end ();
             it != end_it; ++it)
        {
            delete *it;
        }
        words.clear ();
    }

    void add (const std::string & s)
    {
        std::auto_ptr<std::string> v (new std::string (s));
        words.push_back (v.get ());
        v.release ();
    }

    std::string *last_added ()
    {
        return words.back ();
    }

    const std::string *last_added () const
    {
        return words.back ();
    }

private:
    std::vector<std::string *> words;
};

int main ()
{
    store2 store;
    store.add("one");
    std::string* s1 = store.last_added();
    std::cout<<*s1<<std::endl;
    store.add("two");
    std::cout<<*s1<<std::endl; // no crash :-)
}

Существует также класс ptr_vector в Boost, который нацелен на то, чтобы сделать это решение более пригодным для повторного использования и надежным (т.е. автоматически управляет памятью, поэтому вам не нужно беспокоиться об удалении строки при удалении ее указатель из вектора и т. д.).

...