7

コード例を次に示します。

#include <iostream>
#include <vector>

template <typename T>
std::vector<typename T::iterator> f(T t)
{
        std::vector<typename T::iterator> v;
        for (auto i = t.begin(); i != t.end(); ++i)
        {
                v.push_back(i);
        }
        return v;
}

template <typename T>
void print(const std::vector<T>& v)
{
        for (auto i = v.begin(); i != v.end(); ++i)
        {
                std::cout << **i << ' ';
        }
        std::cout << std::endl;
}

int main()
{
        std::vector<int> v{1, 2, 3};
        print(f(v));
        std::vector<std::vector<int>::iterator> itervec = f(v);
        print(itervec);
}

ideoneでの出力は次のとおりです

1 2 3 
163487776 2 3 

質問

出力に変更f(T t)すると、期待どおりになります。f(T& t)コンテナのコピーを扱っているため、技術的には、ベクトルにプッシュバックしているイテレータは、メインで作成したベクトルと同じではないと想定しています。これは正しいです?私が気付いたのは、期待どおりにprint(f(v));出力1 2 3されることですが、最初のイテレータに割り当てるとすぐにitervecガベージになります。これはすべて実装に依存していますか?

4

2 に答える 2

8

はい、イテレータは関数内のローカル オブジェクトに対してのみ有効なイテレータであり、最後にがスコープ外になり破棄され、イテレータが無効になります。vffv

ローカル変数に格納された一時的なコピーではなく、呼び出し元が渡す元のオブジェクトの反復子が、保存する反復子になるように、ベクトルを参照 (またはポインターなど) で渡す必要があります。

表示されている動作は定義されていないため、たまたま最初の 3 つと最後の 2 つが正しく出力されます。

于 2012-04-11T20:41:51.400 に答える
3

はい、一時的なものを受け取り、その一時的な反復子を返すためです。関数の終了後、一時はクリーンアップされ、イテレータが無効になります。

mainただし、両方の参照が渡され、同じオブジェクトprintにアクセスしている場合。このオブジェクトは関数の終了後も存続するため、反復子は無効になりません。

于 2012-04-11T20:41:15.970 に答える