web-dev-qa-db-ja.com

既存のオブジェクトのアドレスをスマートポインターに割り当てる方法

#include <memory>

class bar{};

void foo(bar &object){
    std::unique_ptr<bar> pointer = &object;
}

オブジェクトのアドレスをポインターに割り当てたい。割り当て演算子の右側はstd :: unique_ptrである必要があるため、上記のコードは明らかにコンパイルされません。私はすでにこれを試しました:

pointer = std::make_unique<bar>(object)

ただし、コンパイル中に多くのエラーがスローされます。どうやってやるの?

更新
回答で述べたように-std::unique_ptr::resetメソッドは未定義の動作を引き起こしました。今では、そのような場合には標準のポインターを使用する必要があることを知っています。

20

std :: unique_ptr :: reset を試してください

void foo(bar &object){
    std::unique_ptr<bar> pointer;
    pointer.reset(&object);
}

しかし、これは推奨されないことに注意してくださいunique_ptrは、関数に渡される参照へ。関数の最後で、pointerが破棄されるとき、objectも破棄しようとしますが、関数呼び出し以外では利用できず、アクセスメモリエラーが発生します。 。

例:これはコンパイルされますが、実行時エラーが発生します。

struct bar{ int num;};

void foo(bar &object){
    std::unique_ptr<bar> pointer;
    pointer.reset(&object);
}

int main()
{
    bar obj;
    foo(obj);
    obj.num; // obj is not a valid reference any more.
    return 0;
}

一方、 shared_ptr の使用を検討することもできます。これは、 nique_ptrまたはshared_ptr? の決定に役立ちます。

16
Raydel Miranda

別のunique_ptrまたはnullptrのみを割り当てることができます。考えてみると、これも理にかなっています(resetでやりたいことができますが、これはunique_ptrのバグまたは欠陥だと思います)。

unique_ptrは、ポイント先オブジェクトの排他的所有者です。範囲外になると、オブジェクトが削除されます。
これは、関数にsinkセマンティクスがあることを意味します。渡すポインター(または、むしろ指す先のオブジェクト)は消費されます。つまり、関数内で「消える」(沈みます)。参照によってオブジェクト(必ずしもヒープに割り当てられないオブジェクト) 、自動ストレージを備えたオブジェクトを渡すと驚きの準備ができます!)突然消えてしまいます。

シンクのセマンティクスは適切に伝達される必要があります。関数パラメーターとしてunique_ptrを渡す必要があります。一意のポインターはコピーできないため、その関数のユーザーにstd::moveの使用を強制し、実際に起こっていることのawarenessを作成します。

オブジェクトが「消える」ことは意外な驚きであり、これは意図せずに起こるだけではありません。

4
Damon

失望させてくれますが、そうではありません。動的に割り当てられたオブジェクトまたはスタックによって割り当てられたオブジェクト、あるいは、個別に割り当てられていない動的に割り当てられた配列内のオブジェクトを指すことができる参照があります。

そのアドレスでdeleteを自動的に呼び出すクラスにそのアドレスを配置する必要があります。これは、上記のほとんどの状況では無効です。それは間違いです。したがって、参照を渡し、参照のアドレスをスマートポインターに配置することは、決して行わないでください。特に、reset()ではそうではありません。

せいぜい、あなたがしたいことは、新しく割り当てられたオブジェクトでスマートポインタを初期化することです、例えば:

auto ptr = std::unique_ptr<X>(new X(p1, p2));

参照のアドレスを取得しないでください。今まで。理由もなく。それは道徳的に間違っています。参照アドレスの使用が無効だからではなく、有効に使用できるからです。それは、2か月後に新しい同僚がスマートポインターでそのアドレスを使用したいと思うからです。なぜなら、それが最近行われたことを聞いたからです。それは間違っている、痛いほど間違っている。

3
Dorin Lazăr

私が見ることができるのは、メモリ内のオブジェクトを指すunique_ptrオブジェクトを持ちたいが、メモリの所有権を譲渡したくないということです。

オブジェクトのカスタム削除機能を作成する必要がありますが、実際にはオブジェクトは削除されません。

class bar{};
struct barfakedeleter
{
   void operator()(bar*){/* do nothing here*/}
};

unique_ptrは、2番目の引数がオブジェクトの削除者であるテンプレートです。デフォルトではdefault_deleterですが、この偽物と交換できます:

void foo(bar& object) 
{
unique_ptr<bar,barfakedeleter> pointer(&object);
....
}

編集後:shared_ptrでできることと同じですが、shared_ptrはオブジェクトの継承ツリー内で他のshared_ptrにキャストできるため、削除者はクラステンプレート引数に保存されませんが、インスタンスメンバーとしては過去のものです。これにより、実際にはIMOが使いやすくなります。

void foo(bar& object)
{
   shared_ptr<bar> pointer(&object,[](bar*){}); // just use anonymous function, which will not delete the object
}

リソースのカスタムリリースも実行できます。

shared_ptr<ObjectClass> pointer(GetObject(),[](ObjectClass* obj){ ReleaseTheObject(obj);});
1
Milan