2016-03-28 8 views
2

私のコードはうまくコンパイルされますが、これは私を悩ませているものです。私はstackoverflowで答えを見つけることができませんでした。次の汎用コンストラクタは、コンストラクタ内のクラスインスタンスにshared_ptrを渡す方法の1つです。なぜconst shared_ptrをコピーしてもconstには違反しないのですか?

MyClass { 
    MyClass(const std::shared_ptr<const T>& pt); 
    std::shared_ptr<const T> pt_; //EDITED: Removed & typo 
}; 

MyClass::MyClass(const std::shared_ptr<const T>& pt) 
    : pt_(pt) 
{ } 

これはうまくコンパイルされます。私の質問は次のとおりです:私の理解では、このようなパラメータconstを宣言します:

void myfunc(const T& t) 

約束しないでください。 しかし、shared_ptr ptをpt_にコピーすることで、shared_ptr ptの使用回数を効果的に増やすことはできません。

これは私の側のshared_ptrsの基本的な誤解かもしれませんか?

(誰がこれを読んでそれを実装するために探して、thisは、より高度な実装であるかもしれないことに注意)

+0

@LogicStuff:あなたがクラス定義の余分な&を意味するなら、私は自分の投稿を編集しました。しかし、コンストラクタの定義はうまくコンパイルされますか? – Thomas

+1

@Thomasこれで、 'const'オブジェクトをreference-to-non-constにバインドすることはできません。 – LogicStuff

+0

@MichaelBurrが編集しました、あなたはpt_の宣言で私のタイプミスを指摘していたと思います。 – Thomas

答えて

4

一つは、昔ながらのコピーコンストラクタです:

shared_ptr(const shared_ptr& r) noexcept; 

標準は(C++ 11 20.7.2.2.1/18 "のshared_ptrのコンストラクタ")と言うRであれば、」その空のshared_ptrオブジェクトを構築し、それ以外の場合はr "と所有権を共有するshared_ptrオブジェクトを構築します。

標準では、constの参照で「所有権の共有」が達成される可能性については言及していません。いくつかのオプションは次のようになります。

  • 共有所有権のセマンティクスを実装プライベートメンバーが共有所有権が実際にshared_ptrオブジェクトに住んでいない可能性があります実装mutable
  • データ構造をマークすることがあります - 彼らは、オブジェクトの別のセットであるかもしれません例えば、ポインタを介して取得される可能性があります。
+0

Upvoteは、* C++への私の限られた露出の中で、これまで出会っていなかった* mutable *というキーワードに言及しました! – Thomas

1

私の質問は以下の通りです:私の理解では、このようなパラメータのconstを宣言することは...ない約束tを変える。

約束は、ほとんどの場合、観察可能な状態を変更するものではありません。 constオブジェクトは、「変更する」ことが可能ないくつかの方法があります。それは、変更可能な変数を持つ

  1. - これらは、constの制約の下で変更することが意図されているが、設計手法は、これらのはまれであるべきと、観察すべきではないと言います。それらのためのもう1つのより一般的な用途は、計算に高価なものをキャッシュすることです。したがって、値を返す大量の計算を行うconst関数getがあります。これを最適化してキャッシュを作成します。キャッシュはgetコール中に変更する必要がありますが、実際にはgetは常に同じものを返しますので、オブジェクトの状態が変更されたことを誰も観察できません。

  2. 他のオブジェクトへの非constポインタまたは参照があります。これらの場合、集約、それは変化するオブジェクトではなく、他のものです。これは、shared_ptrの場合に起こります。ポインタには、実際にポインタの値を保持する共有参照カウントオブジェクトへのポインタがあります。このようなオブジェクトの報告された状態は変更される可能性があるため、最初は直感的ではありませんが、実際には変更されたオブジェクト自体ではありません。ここでの設計方法はケースバイケースで行われていますが、ポインタをconstへのポインタとして宣言しない限り、言語は決してあなたを保護しません。リファレンスとしてshared_ptrを渡す

+0

ポイント2は私の質問にお答えします、ありがとうございます!これを正しく理解するために、私のshared_ptr ptはクラスのインスタンスのようなものであり、クラスは参照を数える整数などの(非const!)ptrを保持していますか?だから関数shared_ptr.use_count()は実際にはpt自体のメンバを返すのではなく、その整数を返しますか? – Thomas

+1

うん、十分に近い。 'shared_ptr'は実際にはそれほど愚かではありません。ほとんどのスマートは、参照カウントとポインタを保持している不特定のオブジェクト内にあります。最後の 'shared_ptr'が有効範囲外になると、参照カウントが0に下がり、そのオブジェクトがクリーンアップされます。 'shared_ptr'インスタンスのコピーは単にカウントをインクリメントし、それに対する参照をコピーします。私はパフォーマンスなどを改善するために他のものが続くと確信しています...しかし、それは我々がここで心配している限り、不可欠です。 –

1

はあなただけの参照を取る、あなたはここで何をコピーしていない、その参照count.Moreoverを増加させないので、参照カウントは変更されません。

共有ポインタへの参照をクラスメンバとして使用することは、通常はあなたが望むことではないことに注意してください。これにより、ポインタを使用したいときにポインタがまだ生きているという保証はありません。これは基本的に共有ポインタを使用するときの目標です。

あなたの編集に対する応答:共有ポインタメンバーを使用すると、実際にコピーが作成され、参照カウントが増加します。これはconstオブジェクトをコピーできるので可能です。あなたが言いました、このguaraanteeは存在しません - 本質的には、キーワードmutableはそれを防ぎます。 std::shared_prt<>が持たなければならないというメンバーの

+0

これはどのように関連していますか?質問はconstポインタではなくconstポインタです... – Amit

+0

@Amit:質問は共有ポインタの参照カウントについてです...私は私の質問で答えます。あなたの答えに)。 – davidhigh

+0

あなたは絶対に正しいです。私は豊富な 'const'sによって捨てられました:-) – Amit

2

constは、それが意味するものを意味します。その意味を文書化する必要があります。

通常、「ny状態の一部のサブセットは変更されません」という意味です。共有ptrの場合、変更できない状態のサブセットは「私が指しているもの」です。

カウントが変更されることがあります。内容が変わることがあります。 constは、「スレッドセーフ」を意味すると解釈することができるC++のstdライブラリで

、 - const操作はスレッドセーフであり、あなたがstd容器に入れた場合ので、順番にstdコンテナはスレッドセーフconstの事業を展開しています。

スレッドセーフで、私は同期を意味するものではありません - 私は2つの異なるスレッドは、両方のconstのものを行うことは、大丈夫です。スレッドがconst以外のものを実行している場合、すべてのベットはオフです。

これにより、リーダライタロックロジックが簡単になります。

そして、取り付けなおしのptrがない間refは確かに、スレッドセーフされて追加/削除など...

3

参照カウントを共有ポインタインスタンスに格納されていないので、あなたの質問に簡単な答えは、ではありません参照カウントを保持している外部オブジェクト内に存在します。 shared_ptrを作成すると、参照カウントが外部オブジェクトに追加されます。

のshared_ptrは、オブジェクトへのポインタと制御ブロックへのポインタが含まれています実装

1

Aは、以下のようにポインタを概念的にレイアウトされている共有説明スティーブンT. Lavavejによってthis lectureをチェックしてください。これは、shared_ptrオブジェクト自体ではなく、pointeeの存続時間を制御する制御ブロックです。制御ブロックは、参照数が増減したことを制御ブロックに通知するラッパーと一部のコードです。これは、参照カウント、デリター、およびポインターの元のインターフェースへのポインターを保管するコントロール・ブロックです(したがって、ポインター・キャストがあったとしても、正しいインターフェースに対して削除することができます)。

* shared_ptr object * 
| pointer to object | ---------------> object 
| pointer to control block |----+ +> (possibly different interface 
           | | but still same object) 
           | | 
* control block * <----------+ | 
| reference count |    | 
| deleter   |    | 
| pointer to object | --------------+ 

のshared_ptrのメモリは、このようなものになりますので:

template<class T> 
struct shared_ptr { 
    T* ptr; 
    control_block* pctrl; 
}; 

をそれはshared_ptrのがconstの場合でも、コピーを取ってのshared_ptrの内部状態のいずれかの変異を必要としないことを明らかになることを開始する必要があります。この突然変異は、に向けられた制御ブロックでshared_ptrによって発生します。

したがって、契約は壊れていません。あなたがp自体を変更

T* const p; 

を宣言しているかのように可能ではありませんが、(*p)を変更することは完全に合理的です。

関連する問題