2016-01-02 12 views
10

ポインタメンバー変数を持つクラスが必要です。このポインタは、スタック割り当てまたはヒープ割り当て可能なオブジェクトを指している必要があります。ただし、このポインタには所有権がありません。つまり、ポインタが有効範囲外になったときには、削除は一切呼び出されません。私は生のポインタが問題を解決できると思います...しかし、生のポインタよりも優れたC++ 11のアプローチがあるかどうかはわかりません。所有権のないスタックオブジェクトへのポインタ

例:

class foo{ 
public: 
    bar* pntr 
}; 

int main(){ 
    bar a; 
    foo b; 
    b.pntr=&a; 
} 

答えて

17

生ポインタはここで完全に問題ありません。 C++ 11には、所有していないオブジェクトを扱う他の "ダム"スマートポインタがないため、C++ 11スマートポインタは使用できません。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4282.pdf

がすでにstd::experimental::observer_ptrとして実験的に(T.C @おかげでヒントを。)実装:非所有するオブジェクトのための「愚かな」スマートポインタのための提案があります。 @ T.Cで述べたように、

#include <memory> 

int main() 
{ 
    int a{42}; 

    auto no_op = [](int*){}; 
    std::unique_ptr<int, decltype(no_op)> up(&a, no_op); 
} 

か:

もう一つの選択肢は、何もしないカスタム削除手段でスマートポインタを使用することです。コメントでは、std::reference_wrapperです。

オービットの@ Lightness Racesに記載されているように、std::weak_ptrもまた、所有していないスマートポインタであるため、解決策になる可能性があります。しかし、std::weak_ptrは、または別のstd::weak_ptrからのみ構成できます。重大な欠点は、std::shared_ptrが(内部リファレンスカウントメカニズムのため)「重い」オブジェクトであることです。この場合でもstd::shared_ptrには簡単なカスタムデリターが必要です。そうでない場合は、自動変数へのポインターとしてスタックが壊れます。

+3

あなたは本当にとリンクする必要があります[最新のリビジョン(N4282)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4282.pdf)、または[ ' std :: experimental :: observer_ptr'](http://en.cppreference.com/w/cpp/experimental/observer_ptr)を参照してください。また、 'reference_wrapper'はポインタが決してnullでない場合のオプションです。 –

+0

@ T.C。ありがとう、終わった。 – vsoftco

+0

@ T.C。 Btw、 ''を持つ実装を知っていますか?私はg ++ 5.3とclang ++ 3.7を試していますが、ヘッダーは実装されていません。 – vsoftco

3

生のポインタを使用するには、リソースの所有権がに指摘しているあなたは、ポインタを聞かせするつもりはないとして、ここで完全に大丈夫です。

-3

オブジェクトを動的に割り当てるだけで、shared_ptrを使用します。はい、実際には削除されますが、それが参照付きの最後のものである場合に限ります。さらに、他人がそれを削除するのを防ぐ。メモリリークやポインタのぶつかりを防ぐために、これはまさに正しいことです。また、pointeeの生涯の要件が異なる場合は、おそらくあなたの利点に使用できる関連するweap_ptrもチェックしてください。

+2

これは間違っています。ポインタが自動変数に向いていると、スタックが壊れてしまいます。 – vsoftco

+0

良い点、私はこの部分についてはっきりしていませんでした。私はそのような共通の落とし穴を避けるために、どんな場合でも指示を読むことをお勧めします。 –

+0

私はこの部分の概念(Urlichなど)に同意します:C++はあまりにも多くのメモリモデル(大きなアプリケーション、一般的なコンピューティング用)を持っていますが、この "overdesign"割り当てられた/ etcスマートポインタ。反対に、低いハードウェアプロジェクトではより積極的なコードを使用する必要があります。 BTWスタックは、多くのuC上で非常に限られたリソースです –

0

「より良いアプローチ」とは「より安全なアプローチ」を意味する場合は、「非所有」のスマートポインタをここに実装しました:https://github.com/duneroadrunner/SaferCPlusPlus。 (恥知らずなプラグ警告が、私は、それはここでは関係だと思う。)だからあなたのコードは次のようになります。

#include "mseregistered.h" 
... 

class foo{ 
public: 
    mse::TRegisteredPointer<bar> pntr; 
}; 

int main(){ 
    mse::TRegisteredObj<bar> a; 
    foo b; 
    b.pntr=&a; 
} 

TRegisteredPointerは、目標が破壊されますときに知っていることで生のポインタより「賢く」です。たとえば、

int main(){ 
    foo b; 
    bar c; 
    { 
     mse::TRegisteredObj<bar> a; 
     b.pntr = &a; 
     c = *(b.pntr); 
    } 
    try { 
     c = *(b.pntr); 
    } catch(...) { 
     // b.pntr "knows" that the object it was pointing to has been deleted so it throws an exception. 
    }; 
} 

一般に、TRegisteredPointerは、std :: shared_ptrと比べてパフォーマンスが低下します。スタック上にターゲットオブジェクトを割り当てる機会があるときはずっと低くなります。それでもかなり新しく、まだよく書かれていませんが、ライブラリの使用例がコメント付きで含まれています(ファイル "msetl_example.cpp"、下半分)。

ライブラリにはTRegisteredPointerForLegacyも用意されています。これは、TRegisteredPointerよりもやや低速ですが、ほとんどの状況でローポインタの代替として使用できます。 (特にターゲットタイプが完全に定義される前に使用することができますが、TRegisteredPointerではそうではありません)

質問の感想の点では、私はそれが有効だと思います。今やC++プログラマは、少なくとも無効なメモリアクセスの不必要なリスクを回避するオプションを持つべきです。生のポインタも有効なオプションにすることができますが、私はそれがコンテキストに依存すると思います。セキュリティがパフォーマンスよりも重要な複雑なソフトウェアの場合は、より安全な方法が良いかもしれません。

0

生のポインタの問題は、それがまだ有効なオブジェクトを指している場合に指示する方法はありませんということです。幸いにも、std::shared_ptrにはaliasing constructorがあり、これを使用して自動的に記憶期間を持つクラスメンバーにstd::weak_ptrを有効にすることができます。例:

#include <iostream> 
#include <memory> 

using namespace std; 

struct A { 
    int x; 
}; 

void PrintValue(weak_ptr<int> wp) { 
    if (auto sp = wp.lock()) 
     cout << *sp << endl; 
    else 
     cout << "Object is expired." << endl; 
} 

int main() { 

    shared_ptr<A> a(new A); 
    a->x = 42; 
    weak_ptr<int> wpInt (shared_ptr<int>(a, &a->x)); 

    PrintValue(wpInt); 
    a.reset(); //a->x has been destroyed, wpInt no longer points to a valid int 
    PrintValue(wpInt); 

    return 0; 
} 

プリント:

オブジェクトの有効期限が切れています。

このアプローチの主な利点は、weak_ptrがスコープの外に出ると、削除されたオブジェクトを防ぐことはできませんが、オブジェクトがもはや有効であるときに、同時に、それは安全に検知できないということです。欠点は、スマートポインタのオーバーヘッドが増えていることと、オブジェクトに最終的にshared_ptrが必要なことです。私。スタックに割り当てられたオブジェクトに対してはこれを排他的に行うことはできません。

関連する問題