2016-12-30 4 views
0

私はそれを表現する方法が少し奇妙に聞こえますが、それは単に私がどのようにフレーズできるか分かりません。私はA *を実装しようとしています。以前はやっていましたが、私のパスをトレースすることに1つの問題があったので、小さなテストを実行することにしました。問題は、このようなものを行ってきました:メンバー変数と同じタイプのポインタを持つオブジェクトへのポインタを持つことができないのはなぜですか?

私は少しこのようになりますクラスがあります。

class Number { 
public: 
    int xPos; 
    int yPos; 

    Number *prevNum; 
    Number(int x, int y) { 
     xPos = x; 
     yPos = y; 
    } 
}; 

を、main関数で、私は、それを何らかの理由でこの

int main() { 
    Number n(2, 2); 
    Number *current = &n; 
    vector<Number> nums; 
    nums.push_back(*current); 
    for (unsigned i = 0; i < 15; i++) { 
     Number n(current->xPos + 1, current->yPos); 
     n.prevNum = current; 
     nums.push_back(n); 
     current = &n; 
     cout << current->xPos + 1 << " "; 
    } 
    for (unsigned i = 0; i < nums.size(); i++) { 
     if (nums.at(i).prevNum) { 
      cout << nums.at(i).prevNum->xPos << " "; 
     } 
    } 
    return 0; 
} 

を行います

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 555437610 2 17 17 17 17 17 17 17 17 17 17 17 17 17 17 

毎回555437610が異なるため、私はエラーが発生する可能性がありますポインタ。メンバー関数* prevNumを無限に入れ子にすることはできませんか?私はそれをどのように記述するのか完全にはわかりません。

+3

あまりにも厄介ではありませんが、クラスが_Number_を表していますか?名前の変更は理にかなっているかもしれません。 – byxor

+4

あなたのコンストラクタは 'prevNum'を' nullptr'に設定するべきです。 –

+0

'n'はforループのローカル変数です。したがって、それらのすべての&nはループ外では定義されていません。 –

答えて

3

あなたの問題は

current = &n; 

ここでは、ループのローカル変数のアドレスを取っているとあります。反復の最後に、変数が破棄されます。これは、もはや存在しないオブジェクトへのポインタを持つことを意味します。そのポインタを参照解除すると、未定義の動作になります。

動作を定義したままにしておきたい場合は、オブジェクトへのポインタをベクトルに格納する必要があります。そのポインタはpush_backへの呼び出しの後で無効になることがありますが、それ以前に使用するので問題ありません。あなたは大丈夫でなければなりません

current = &nums.back(); 

また、以前のポインタを保存することに問題があります。ベクトルから要素を取得する場合、ベクトルが領域を再割り当てすると、ぶら下がったポインタが残されます。これを実現するには、何らかの種類のshared_ptrが必要になると思います。

1

nの範囲は、forループのみです。したがってcurrent = &n;は、すぐに範囲外になるオブジェクトを指すようにcurrentを設定します。

nums.push_back(n);nをベクターにコピーします。&nums.back()currentに割り当てる必要があります。実際に

次のように、あなたのプログラムを簡素化することができる。

struct Number { // Now a proper aggregate 
    int xPos; 
    int yPos; 

    Number *prevNum; 
}; 

vector<Number> nums {{1, 2, nullptr}}; 
nums.reserve(16); 
for (unsigned i = 0; i < 15; ++i) { 
    Number& back = nums.back(); 
    nums.emplace_back({back.xPos + 1, back.yPos + 1, &back}); 
    cout << nums.back().xPos + 1 << " "; 
} 
+0

これにはまだUBがあります。 '&back'を保存すると、ベクトルが再割り当てされても動作しません。 – NathanOliver

+0

@ NathanOliver - 事前にスペースを予約するだけです。 – StoryTeller

+0

それは動作します。 – NathanOliver

2

あなたは持っている:

あり
for (unsigned i = 0; i < 15; i++) { 
    Number n(current->xPos + 1, current->yPos); 
    n.prevNum = current; 
    nums.push_back(n); 
    current = &n; 
    cout << current->xPos + 1 << " "; 
} 

nは、ループの終了時に破壊されますローカル変数です。ローカル変数へのポインタを格納しておき、後でそれを使用しています。

プログラムに未定義の動作があります。


prevNumメンバー変数が必要な理由はわかりません。 あなたはそれを完全に取り除くことができます。

#include <iostream> 
#include <vector> 

using namespace std; 

class Number { 
public: 
    int xPos; 
    int yPos; 

    Number(int x, int y) { 
     xPos = x; 
     yPos = y; 
    } 
}; 

int main() { 
    Number n(2, 2); 
    vector<Number> nums; 
    nums.push_back(n); 
    for (unsigned i = 0; i < 15; i++) { 
     Number n(2+i+1, 2); 
     nums.push_back(n); 
     cout << 2 + i+1 << " "; 
    } 
    cout << endl; 
    for (unsigned i = 0; i < nums.size(); i++) { 
     cout << nums.at(i).xPos << " "; 
    } 
    cout << endl; 
    return 0; 
} 
関連する問題