2010-12-08 25 views
3

this questionで実験すると、私は完全に理解していない例を作りました。特に、私はポインタ、リファレンス、boost :: shared_ptrに関する誤解を強調しています。このコードを実行するboost :: shared_ptr質問。なぜこれは機能しますか?

int& r = *(new int(0));//gratuitous pointer leak, got to initialize it to something 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    r = *sp; 
    cout << "r=" << r << endl; 
} 
cout << "r=" << r << endl << endl; 

int* p; 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    p = &*sp; 
    cout << "*p=" << *p << endl; 
} 
cout << "*p=" << *p << endl; 

が出力にこのような何か与える:

r=100 
r=100 

*p=100 
*p=13 

をなぜ参照はのshared_ptrの死を生き残るが、ポインタはないでしょうか?ここではその中の回答で問題があります


は、2つの直径方向に対向すると矛盾したソリューションであり、真理であり、その上に無コンセンサスがあるように思われます。私は、shared_ptrが削除された後にリファレンスを使用する機能が欲しいですが、無効な場合はこれを本当に理解する必要があります。

誰かが、参照の未定義の動作を示す簡単な例を投稿する可能性があります。

+0

ブロックの順番を逆にしても、参照は引き継がれ、ポインタは保持されません。しかし、これは運が単なる運だと言っていますよね? – JnBrymn

+0

私のコメントは間違っていた、@ FredOverflowの答えを参照してください。申し訳ありません... –

+0

'*(new ...) 'は書かないでください。実際には、「ヒープからいくつかのメモリを割り当てて、メモリがヒープから来たことを忘れてください」と言っています。参照ではなく値に割り当てると、回復不能なメモリリークが発生します。参照に割り当てても、クリーンアップには 'delete&r'が必要です。これは恐ろしく非慣用的です。 –

答えて

12

r = *sp;はあなたが思うとはしません。 には、という参照先、つまり1行目のヒープ上に作成した匿名のintオブジェクトが割り当てられます.C++で参照を再配置することはできません。ここで

は標準が基準式を評価についてこう言われる、式は当初タイプ「Tへの参照を」持っている場合

、 タイプは前任意のさらなる分析にTに調整されています。 式は、参照番号, で表されるオブジェクトまたは関数を指定し、式は式に応じて左辺値またはx値です。

「参照自体」にアクセスする方法はありません。それは単にC++には存在しません。

たぶん、このコードは、それがより明確になります:r = bは本当にa = bを意味するので

int a = 42; 
int b = 97; 

int&r = a; // r is just an alias (another name) for a 
    r = b; // assigns b to a (does NOT bind r to b, that's impossible in C++!) 

最後の行を実行した後、abの両方が、97が含まれています。

+0

だから私はこのようなコードを書いているかのようです: '(&r)=(' – JnBrymn

+1

いいえ、あなたがコーディングしているかのように...あなたの息を止めてください... 'r = * sp'。' r 'は、既存の値の新しく割り当てられた名前として最もよく考えられます。共有ポインタが指す値を読み込み、' r'が参照するメモリのチャンクに割り当てます。 'r'は異なる値のメモリを参照することは不可能です; rは** value **の新しい名前です。値は移動しません(少なくとも0x以前ではありません)。 –

+0

@FredOverflow So私の例では、対応するshared_ptrが削除された後で参照を使用することはOKであることを示しています。削除された値を参照する参照がどのように動作を定義できるのか分かりません...現在のケースでは – JnBrymn

2

pは未定義で、rは第2のケースでコピー

int& r = *(new int(0)); 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    r = *sp; // copy 
    cout << "r=" << r << endl; 
} 
cout << "r=" << r << endl << endl; 

int* p; 
{ 
    boost::shared_ptr<int> sp(new int(100)); 
    p = &*sp; 
    cout << "*p=" << *p << endl; 
} 
cout << "*p=" << *p << endl; // Undefined, pointer points to deleted int 
+0

*(new int(0))を指し続ける場合、どのように100を印刷できますか? – ronag

+0

@ronag:ポインタが指し示す値が参照ポイントのどこにコピーされたか。 –

+0

訂正していただきありがとうございます。 – ronag

0

で、あなたのint -objectが破壊されます。最初のケースではそうではありません。

最初のケースでは、外側範囲にnewの新しいintオブジェクトを作成します。内側のスコープでは、2番目のintオブジェクトを作成します。shared_ptrも作成し、intオブジェクトを所有しています。このshared_ptrは、内部スコープを閉じるときに範囲外になります。したがって、スコープが破壊されます。他のshared_ptr(元のものから作成されたもの)があなたのintオブジェクトをもう参照していないので、shared_ptrデストラクタはそれが参照するオブジェクトも破棄します。それは大丈夫です。ただし、その範囲の途中でrの値を*sp(100)の値に再割り当てします。したがって、*spの値を、spが破棄される前に、rに保存します。

注:最初のコード行で行う方法と同じように、intオブジェクトを作成することは確かに疑わしいスタイルです。そのintオブジェクトを明示的に削除しないと、これはメモリリークです。それを破壊する方法は、特にシンボルrが今でも削除されたintオブジェクトを参照しているため、実際には醜いと思われるdelete &rになります。これをしないでください!

2番目のケースでは、最初にintポインタを作成しますが、intオブジェクトは作成しません。内部範囲は、新しいintオブジェクトの値を外側スコープ変数(p)に保存しないが、intオブジェクトのアドレスを保存することを除いて、以前とほぼ同じです。 intオブジェクトが(以前と同じ理由で)内部スコープの終わりで破棄されるため、pは、既存のintオブジェクトを指していませんが、以前は一度intオブジェクトを保持していたメモリ内の場所を指していません。 *pから得られる値は未定義です。あなたはまだ100を得ることができ、他の値を得ることができ、もはや保持していないメモリ位置を間接的に参照するので、ここでプログラムをクラッシュさせることさえあります。

ので要約し、そしてあなたの最後の質問に答えるために:それはまだ既存のオブジェクトを参照するため

を参照は、生き残っています。ポインタは存在しないオブジェクトを指しているため、ポインタは存在しません。

関連する問題