2

在下面的程序中,一个字符串被添加到一个空的存储中。然后这个存储元素的地址存储在指针's1'中。然后添加另一个字符串,这会以某种方式导致指向原始元素的指针失败。

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

class store2
{
    public:
        void add(std::string s) {words.push_back(s); last_added2 = &words.at(words.size() - 1);}
        std::string* last_added() {return last_added2;}

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

void 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; // crash
}
4

4 回答 4

3

当您向 中添加新项目时std::vector,向量可能需要扩展其缓冲区,这样做可能会将缓冲区移动到不同的内存区域。因此指向其元素的指针变得无效。简而言之,在调整向量大小后,指向向量项的指针不保证有效,并且push_back如果没有足够的保留空间,可能会调整向量的大小。

您可以在开始时为向量保留空间,但是您可以限制分配到向量中的项目数量。

于 2011-01-27T15:41:13.527 回答
1

如果您需要确保指向集合的指针保持有效,您可能需要除向量之外的其他内容(例如,您可以使用 a std::dequeorstd::list代替——std::deque通常在两者之间首选)。

或者,您可以返回字符串的索引,并提供一个成员函数,在使用该向量时将其索引到该向量中,而不是返回一个指针(无论如何通常都是一个坏主意)。

于 2011-01-27T15:55:40.410 回答
1

你有什么特别的理由要使用指针(堆)吗?如果没有,请执行以下操作:

   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;
    }

;

于 2011-01-27T15:57:59.360 回答
0

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 :-)
}

Boost 中还有一个ptr_vector类,旨在使这种解决方案更可重用和更健壮(即自动管理内存,因此您不必担心在从向量等中擦除其指针时删除字符串)。

于 2011-01-27T15:55:42.623 回答