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

コレクションへのポインターが有効なままであることを保証する必要がある場合は、ベクトル以外の何かが必要になる可能性があります (たとえば、代わりにstd::dequeorを使用できますが、一般的には 2 つの間で優先されます)。std::liststd::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 に答える