字符串和商店

时间:2011-01-27 15:37:49

标签: c++ pointers set elements stdvector

在下面的程序中,字符串被添加到空商店。然后,该存储元素的地址存储在指针'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 个答案:

答案 0 :(得分:3)

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

您可以在开头为矢量预留空间,但是您可以对可以分配到矢量中的项目数量进行限制。

答案 1 :(得分:1)

如果您需要确保指向集合的指针仍然有效,您可能需要除向量之外的其他内容(例如,您可以使用std::dequestd::list代替{{1}通常在两者之间是首选的。)

或者,您可以返回字符串的索引,而不是返回指针(通常是一个糟糕的主意),并提供一个成员函数,该函数在使用时会转换为向量。

答案 2 :(得分: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;
    }

答案 3 :(得分:0)

std::vector的迭代器在修改其内容时可能会失效。请参阅vector iterator invalidation

如果你真的想保留现有的接口并保留插入向量的元素的指针,你可以按指针而不是按值存储字符串,例如:

#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类,旨在使这种解决方案更具可重用性和鲁棒性(即自动管理内存,因此您不必担心从向量中删除指针时删除字符串等)。