3

次のようなベクトルのベクトルへのペアのマップがあります。

std::map<std::pair<uint16, uint16>, std::vector<std::vector<uint32> > >

マップは、クラスのコンストラクターに取り込まれます。std::vector<std::vector<uint32> >このクラスは、 (マップ値の部分)へのポインターを返す public メソッドを次のように提供します。

typedef std::pair<uint16, uint16> key;
typedef std::vector<std::vector<uint32> > value;

value* FindValues(key someKey) {
    std::map<key, value>::const_iterator it;
    it = someStore.find(someKey);
    if (it != someStore.end()) 
        return &(value)it->second;
    return NULL;
}

これは奇妙なときです。FindValues によって返されたベクトルを反復処理する場合、すべての子ベクトルは、最初の値として大きな負の数 (-1818161232 など) を持ちます。しかし、次のような関数を使用すると:

value FindValues(key someKey) {
    std::map<key, value>::const_iterator it;
    return someStore.find(someKey)->second;
}

...それなら値は正常です。これは、すべての子ベクトルのインデックス 0 の値に対してのみ発生します。ただし、2 番目の方法では、(明らかな理由で) キーが見つからない場合、アプリケーションはセグメンテーション違反を起こします。私は何を間違っていますか?

4

3 に答える 3

5

returnステートメントが本当に次のように見える場合

return &(value) it->second;

次に、それについて言えることがいくつかあります。

  1. コンパイラが診断メッセージを発行せずに受け入れた場合、コンパイラは壊れています。C++ では、組み込み単項&を非参照キャストの結果に適用することは違法です。この(value) it->second式は、一時オブジェクトである右辺値を生成します。を使用してそのようなオブジェクトのアドレスを取得することはできません&。コードはコンパイルすることさえできません。

  2. コンパイラがそれをある種の奇妙な「拡張」として受け入れる場合、それは実際に一時オブジェクトのアドレスを取得して返していることを意味します。一時オブジェクトはすぐに破棄され、ポインターはガベージを指したままになります。そのようなポインターを介していくつかの奇妙な値が表示されるのも不思議ではありません。

  3. ある種のキャストの必要性const_iteratorは、検索の結果を格納するために使用したという事実から生じます。どうやら、あなたは誤った方向への試みを行い、キャストで constness をキャストしたようit->secondです(value)。それを行う正しい方法は次のようになります

     return const_cast<value *>(&it->second);
    

    でも、const_iteratorそもそもなんで使ったの?正しいことは、通常のを使用してiterator、単に行うことです

     return &it->second;
    

    余分なキャストなしで。

  4. FindValue作成しようとしているメソッドの種類を決定する必要があります。これが定数メソッドであると想定されている場合は、戻りconst value *、次のように宣言する必要があります。const

    const value* FindValues(key someKey) const
    

    もちろん、const_iteratorこの場合は inside を使用する必要があります。

    FindValue非定数メソッドであることが想定されている場合は、現在の宣言を保持できます

    value* FindValues(key someKey)
    

    しかし、普通のiterator内部を使用してください。

    あなたが今持っているのは、2つのハイブリッドのようなものであり、それがあなたを奇妙なキャストに頼らせるものです. (実際、クラスにはおそらく両方のバージョンが必要になるでしょう。一方は他方を介して実装できます。)

于 2012-07-12T21:13:43.637 に答える
3

あなたtypedefのはかなり誤解を招くものです。これは間違った行です:

return &(value)it->second;

単純な C スタイルの型キャストのように見えるものは、実際にはstd::vectorのコピー コンストラクターの呼び出しです。この行は次のように書き換えることができます

return &std::vector<std::vector<uint32> >(it->second)

この行を次のように書き換えると、奇妙な結果の理由が明らかになります。

std::vector<std::vector<uint32> > result (it->second);
return &result;

実際には、関数が戻るとすぐに破棄されるローカル オブジェクトのアドレスを返しています。

于 2012-07-12T21:14:59.540 に答える
0

したがって、このバリアントの方が優れています。

typedef std::pair<uint16, uint16> key;
typedef std::vector<std::vector<uint32> > value;

value* FindValues(key someKey) {
    std::map<key, value>::const_iterator it;
    it = someStore.find(someKey);
    if (it != someStore.end()) 
        return &const_cast<value&>(it->second);
    return 0;
}
于 2012-07-12T21:06:55.010 に答える