web-dev-qa-db-ja.com

shared_ptrを明示的に削除する

簡単な質問:boost::shared_ptrを自分で明示的に削除できますか?あなたは今までにすべきですか?

明確に言うと、shared_ptrが保持しているポインターを削除するつもりはありません。実際のshared_ptrそのものを意味しました。私はほとんどの人がそれをしないことを提案していることを知っているので、明示的にそれをしても大丈夫かと思っていました。

19
garsh0p

あなたの質問は明確ではありません。 shared_ptrを動的に割り当てた場合、いつでもdeleteに許可されます。

しかし、shared_ptrによって管理されているオブジェクトを削除できるかどうかを尋ねる場合、答えは...です。 shared_ptr::uniqueがtrueを返す場合、shared_ptr::resetを呼び出すと、管理対象オブジェクトが削除されます。ただし、shared_ptr::uniqueがfalseを返す場合、そのオブジェクトの所有権を共有しているshared_ptrsが複数存在することを意味します。この場合、resetを呼び出すと、参照カウントが1だけ減ります。そのオブジェクトを管理する最後のshared_ptrがスコープ外になるか、オブジェクトが削除されると、オブジェクトの実際の削除が行われます。それ自体reset

編集:
編集後、動的に割り当てられたshared_ptrの削除について尋ねているようです。このようなもの:

auto sp = new boost::shared_ptr<int>( new int(42) );

// do something with sp

delete sp;

これは許可されており、予想どおりに機能しますが、通常とは異なる使用例です。唯一の注意点は、spの割り当てと削除の間に、オブジェクトの所有権を共有する別のshared_ptrを作成した場合、spを削除してもオブジェクトは削除されないことです。これは、オブジェクトの参照カウントが0になったときにのみ発生します。

25
Praetorian

[編集:delete a _shared_ptr_は、newで作成された場合に限り、他のタイプと同じことができます。なぜnewで_shared_ptr_を作成するのか考えられませんが、あなたを止めるものは何もありません。]

さて、あなたはcoulddelete ptr.get();と書きます。

そうすることで、other共有所有者が_shared_ptr_を使用して削除されたオブジェクトにアクセスするか、オブジェクトの最後の_shared_ptr_が破棄される場合、ほとんどの場合、未定義の動作につながります。オブジェクトが再び削除されます。

いいえ、そうすべきではありません。

_shared_ptr_の目的は、所有権を共有する他の人が存在する可能性があるため、誰も削除する権利または責任を持たないオブジェクトを管理することです。だから、あなたもしたくないはずです。

5
Steve Jessop

参照カウントをゼロに強制することはできません、いいえ。

それが機能するために何が必要かを考えてください。 shared_ptrが使用されている各場所に移動し、クリアする必要があります。

共有ポインターを強制的に削除してNULLに設定した場合、weak_ptrのようになります。ただし、そのshared_ptrを使用するコード内のこれらの場所はすべて、その準備ができておらず、有効なポインターを保持していることを期待しています。 NULLをチェックする理由がないため、これらのコードはクラッシュします。

3
Zan Lynx

カウントの減少をシミュレートする場合は、次のようにヒープで手動で実行できます。

_int main(void) {
    std::shared_ptr<std::string>* sp = new std::shared_ptr<std::string>(std::make_shared<std::string>(std::string("test")));
    std::shared_ptr<std::string>* sp2 = new std::shared_ptr<std::string>(*sp);
    delete sp;

    std::cout << *(*sp2) << std::endl;    // test
    return 0;
}
_

または、次のようにstd::shared_ptr::reset()を使用してスタック上で:

_int main(void) {
    std::shared_ptr<std::string> p = std::make_shared<std::string>(std::string("test"));
    std::shared_ptr<std::string> p2 = p;
    p.reset();

    std::cout << *p2 << std::endl;    // test
    return 0;
} 
_

しかし、それはそれほど有用ではありません。

1
wulfgarpro

いくつかの(非常に?)まれなケースでは、明示的な削除が便利です。

明示的に削除することに加えて、共有ポインタを「削除」するときに明示的に破棄する必要がある場合があります。

Shared_ptrを不透明な値として渡して、Cコードとインターフェースをとると、物事が奇妙になります。

たとえば、Cで記述されたLuaスクリプト言語との間でオブジェクトを渡すために次のものがあります(www.lua.org)

static void Push( lua_State *L, std::shared_ptr<T> sp )
{
    if( sp == nullptr ) {
        lua_pushnil( L );
        return;
    }

    // This is basically malloc from C++ point of view.
    void *ud = lua_newuserdata( L, sizeof(std::shared_ptr<T>));

    // Copy constructor, bumps ref count.
    new(ud) std::shared_ptr<T>( sp );

    luaL_setmetatable( L, B::class_name );
}

これは、いくつかのmallocされたメモリ内のshared_ptrです。その逆は...(Luaガベージがオブジェクトを収集して「解放」する直前に呼び出されるセットアップ)。

static int destroy( lua_State *L )
{
    // Grab opaque pointer
    void* ud = luaL_checkudata( L, 1, B::class_name );

    std::shared_ptr<T> *sp = static_cast<std::shared_ptr<T>*>(ud);

    // Explicitly called, as this was 'placement new'd
    // Decrements the ref count
    sp->~shared_ptr();

    return 0;
}
0
Nigel Atkinson