2016-11-16 5 views
1

私はEffective C++ 3rd Editionを読んでいました。 70ページで、著者は言う:unique_ptrからrawポインタへの暗黙的な変換はサポートされていますか?

Like virtually all smart pointer classes, tr1::shared_ptr and auto_ptr also overload the pointer dereferencing operators (operator-> and operator*), and this allows implicit conversion to the underlying raw pointers (...)

彼はその後、Investmentという名前のクラスに基づいて、暗黙的な変換をフィーチャーし(一度にtr1の一部であった)shared_ptrに例を示します。まあ

shared_ptr<Investment> pi1(); 
bool taxable1 = !(pi1->isTaxFree()); 
        ^implicit conversion 

shared_ptr<Investment> pi2(); 
bool taxable2 = !((*pi2).isTaxFree()); 
        ^implicit conversion 

私はそれ以来、unique_ptrでいくつかのテストケースを書いており、それらはホールドアップしています。

unique_ptr supporting arraysshared_ptr is also going to(注記を参照)も見つかりました。しかし、私のテストでは、暗黙的な変換は、配列の周りのスマートポインタのために動作していないようです。

例:私は

unique_ptr<int[]> test(new int[1]); 

(*test)[0] = 5; 

...これが有効になりたかったが、それは私のコンパイラ(のVisual C++ 2015のアップデート3)によると、ではありません。

次に、検索を行うと暗黙的な変換が全くサポートされていないという証拠が見つかりました。例えば、https://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-toのように。

この時点で私は疑いがあります。 (標準)がサポートされていますか?そうではありませんか?


注:著者はまた、「dinamicallyに割り当てられた配列のためauto_ptrまたはtr1::shared_ptrのようなものは何もないでもTR1で、存在しない」という65ページの言うことから本は、このトピックに少し時代遅れかもしれません。

+0

'*テスト[0] = 5;'あなたが欽慕'unique_ptr :: operator []'の結果です。もちろん、普通の 'int'では動作しません。 – StoryTeller

+0

@StoryTeller公正で十分です。私はそれが固定されていたと思う... –

+0

'unique_ptr 'には 'operator *()'がありません。 'unique_ptr 'には 'operator []()'がありますが、 'unique_ptr 'には '演算子*()'があります。 'test [0] = 5;' –

答えて

4

さて、ここが問題です。基本的なポインタへの暗黙的な変換はありません。特定のgetメンバ関数を呼び出さなければなりません(これは標準ライブラリのテーマです、std::string::c_strと考える)。

しかし、それは良いことです!暗黙的にポインタを変換すると、unique_ptrの保証を破ることができます。次のことを考えてみましょう:

上記のコードで
std::unique_ptr<int> p1(new int); 
std::unique_ptr<int> p2(p1); 

、コンパイラはp2p1の指示先を渡すために試すことができます! (この呼び出しはとにかくあいまいではありませんが、そうではないと仮定しているためではありません)。彼らは両方ともそれにdeleteを呼ぶでしょう!

しかし、スマートポインタを生のポインタのように使用したいと考えています。したがって、すべての演算子に過負荷がかかります。


今度は、あなたのコードを考えてみましょう:それはint& 生成unique_ptr::operator*を呼び出し

(*test)[0] = 5; 

。次に、添え字演算子を使ってみましょう。それはあなたのエラーです。あなただけのハンドルが提供するoperator[]オーバーロードを使用するよりも、std::unique_ptr<int[]>をお持ちの場合
デビッド・スカーレットが指摘したように

test[0] = 5; 

、それもコンパイルべきではありません。配列バージョンはこの演算子を持つことは想定されていません。落語が示すように

+0

暗黙的に変換するのはいいですが、C++用のObjective Cのようなランタイムインターフェイスを実装するとしたら、(NSString :: alloc()) - > autorelease ()、NSStringとNSObject、NSSpecialStringなどの間でのキャストなどを行うには、Microsoft IUnknownのQueryInterfaceと似たような手段を採用する必要があります。現在のC++では、このプロセスを自動化できるだけです。 – Dmitry

+1

実際には、単一オブジェクトバージョンの 'unique_ptr 'のみが 'operator *()'を持っています。配列バージョン 'unique_ptr 'には、代わりに 'operator []()'があります。したがって、最初の要素を返すのではなく、 '(* test)'はコンパイルすべきではありません。 GCCは次のように述べています: 'error: 'operator *'と一致しません(オペランドの型は 'std :: unique_ptr ')' –

+0

@ドミトリー、私はそれがうまくいくことに同意します。そのためAndrei Alexandrescuは、現代のC++デザイン "; '明示的な '変換演算子では、ほとんどの場合エラーが起こりにくくなります。しかし、標準ライブラリは、私が実際に犯すことのできないより慎重なアプローチに固執しています。 – StoryTeller

1

、暗黙的な変換は、ショーを台無しだろうが、私はこれについて考える別の方法を提案したいと思います:unique_ptrshared_ptrなどの

スマートポインタは、彼らがしようとするため、基礎となる生のポインタを隠そうとします特定の種類の所有権セマンティクスを維持します。そのポインタを自由に取得して渡すと、簡単にそれらのセマンティクスに違反する可能性があります。彼らは(あなたがスマートなポインタにちょうど従うことができ、pointeeのアドレスを得ることができた後であっても)完全にあなたを止めることができなかったので、彼らはそれにアクセスする方法を提供します(get)。しかし、彼らはまだあなたが誤ってそれにアクセスしないように障壁を置くことを望んでいます。

すべてが失われません!ほとんどの他のスマートポインタから暗黙的に構築できるように、非常に弱いセマンティクスを持つ新しい種類のスマートポインタを定義することで、構文上の便利さを得ることができます。考えてみましょう:

// ipiwdostbtetci_ptr stands for : 
// I promise I wont delete or store this beyond the expression that created it ptr 
template<class T> 
struct ipiwdostbtetci_ptr { 
    T * _ptr; 
    T & operator*() {return *_ptr;} 
    T * operator->(){return _ptr;} 
    ipiwdostbtetci_ptr(T * raw): _ptr{raw} {} 
    ipiwdostbtetci_ptr(const std::unique_ptr<T> & unq): _ptr{unq.get()} {} 
    ipiwdostbtetci_ptr(const std::shared_ptr<T> & shr): _ptr{shr.get()} {} 
}; 

だから、この風刺的に名付けられたスマートポインタのポイントは何ですか?これは単なるポインタのようなもので、ユーザーが決してそれを保持しないという契約や、それを作成した式を超えて生きているもののコピーがあり、ユーザーは決して削除しようとしません。これらの制約の後に(コンパイラがそれをチェックすることなく)ユーザによって、生のポインタだけでなく多くのスマートポインタを暗黙的に変換することは完全に安全です。

今、あなたは期待する機能を実装することができipiwdostbtetci_ptrそれらを呼び出す便利な、と(彼らはセマンティクスを尊重うと仮定して):

void f(ipiwdostbtetci_ptr<MyClass>); 
... 
std::unique_ptr<MyClass> p = ... 
f(p); 
関連する問題