40

boost :: shared_ptrは、保存されているポインターを削除せずに解放できますか?

ドキュメントにリリース機能が存在しないことがわかります。また、FAQには、リリース機能が提供されない理由が説明されています。たとえば、一意でないポインターではリリースを実行できません。私のポインタはユニークです。ポインタを解放するにはどうすればよいですか?または、使用するスマートポインタークラスをブーストして、ポインターを解放できるようにしますか?auto_ptrを使用するとは言わないでください:)

4

14 に答える 14

31

しないでください。BoostのFAQエントリ:

Q。 _ shared_ptrがrelease()関数を提供しないのはなぜですか?

A。 _ shared_ptrは、unique()でない限り、所有権を譲渡できません。これは、他のコピーが引き続きオブジェクトを破棄するためです。

検討:

shared_ptr<int> a(new int);
shared_ptr<int> b(a); // a.use_count() == b.use_count() == 2

int * p = a.release();

// Who owns p now? b will still call delete on it in its destructor.

さらに、release()によって返されるポインターは、ソースshared_ptrがカスタム削除機能で作成されている可能性があるため、確実に割り当てを解除するのが困難です。

したがって、これがオブジェクトを指す唯一のshared_ptrインスタンスであり(unique()がtrueを返す場合)、オブジェクトが特別な削除機能を必要としない場合は安全です。このような.release()関数を使用した場合は、まだ設計に疑問があります。

于 2009-10-06T15:45:16.207 に答える
24

偽の削除機能を使用できます。そうすると、ポインタは実際には削除されません。

struct NullDeleter {template<typename T> void operator()(T*) {} };

// pp of type some_t defined somewhere
boost::shared_ptr<some_t> x(pp, NullDeleter() );
于 2009-10-06T14:56:52.450 に答える
7

子供たち、家でこれをしないでください:

// set smarty to point to nothing
// returns old(smarty.get())
// caller is responsible for the returned pointer (careful)
template <typename T>
T* release (shared_ptr<T>& smarty) {
    // sanity check:
    assert (smarty.unique());
    // only one owner (please don't play games with weak_ptr in another thread)
    // would want to check the total count (shared+weak) here

    // save the pointer:
    T *raw = &*smarty;
    // at this point smarty owns raw, can't return it

    try {
        // an exception here would be quite unpleasant

        // now smash smarty:
        new (&smarty) shared_ptr<T> ();
        // REALLY: don't do it!
        // the behaviour is not defined!
        // in practice: at least a memory leak!
    } catch (...) {
        // there is no shared_ptr<T> in smarty zombie now
        // can't fix it at this point:
        // the only fix would be to retry, and it would probably throw again
        // sorry, can't do anything
        abort ();
    }
    // smarty is a fresh shared_ptr<T> that doesn't own raw

    // at this point, nobody owns raw, can return it
    return raw;
}

さて、refカウントの所有者の総数が> 1であるかどうかを確認する方法はありますか?

于 2011-10-08T22:39:20.270 に答える
6

基になるポインタを削除しないように要求できる削除機能を使用する必要があります。

詳細については、この回答(この質問の複製としてマークされています)を参照してください。

于 2013-05-19T11:15:04.197 に答える
4

ポインタが再び何も指さないようにするには、を呼び出すことができますshared_ptr::reset()

ただし、これにより、ポインタがオブジェクトへの最後の参照であるときに指しているオブジェクトが削除されます。ただし、これは、そもそもスマートポインタの望ましい動作です。

オブジェクトを存続させない参照が必要な場合は、を作成できますboost::weak_ptrブーストのドキュメントを参照)。Aweak_ptrはオブジェクトへの参照を保持しますが、参照カウントには追加されないため、弱い参照のみが存在する場合、オブジェクトは削除されます。

于 2009-10-06T14:28:35.960 に答える
3

共有の基本は信頼です。プログラムの一部のインスタンスがrawポインターを解放する必要がある場合、それがshared_ptr間違ったタイプであることはほぼ間違いありません。

ただし、最近、別のプロセスヒープから割り当てを解除する必要があったため、これも実行したいと思いました。std::shared_ptr結局、私はいくつかを使用するという私の以前の決定は考え抜かれたものではないと教えられました。

私はこのタイプをクリーンアップに日常的に使用しました。しかし、ポインタはいくつかの場所で複製されました。実はstd::unique_ptr、(サプライズ)release機能のあるが必要でした。

于 2012-09-11T14:57:28.770 に答える
2

彼らが何をしているのかわからないので、彼らを許してください。この例は、メモリリークなしでboost::shared_ptrおよびmsvsstd:: shared_ptrで機能します!

template <template <typename> class TSharedPtr, typename Type>
Type * release_shared(TSharedPtr<Type> & ptr)
{
    //! this struct mimics the data of std:shared_ptr ( or boost::shared_ptr )
    struct SharedVoidPtr
    {
        struct RefCounter
        {
            long _Uses;
            long _Weaks;
        };

        void * ptr;
        RefCounter * refC;

        SharedVoidPtr()
        {
            ptr = refC = nullptr;
        }

        ~SharedVoidPtr()
        {
            delete refC;
        }
    };

    assert( ptr.unique() );

    Type * t = ptr.get();

    SharedVoidPtr sp; // create dummy shared_ptr
    TSharedPtr<Type> * spPtr = (TSharedPtr<Type>*)( &sp );
    spPtr->swap(ptr); // swap the contents

    ptr.reset();
    // now the xxx::shared_ptr is empy and
    // SharedVoidPtr releases the raw poiter but deletes the underlying counter data
    return t;
}
于 2012-12-04T11:23:20.180 に答える
1

共有ポインタを削除できますが、これは私にはほとんど同じようです。ポインタが常に一意である場合は、それstd::auto_ptr<>が適切な選択です。STLコンテナーでの操作は多くのコピーと一時的な複製を行うため、一意のポインターをSTLコンテナーで使用できないことに注意してください。

于 2009-10-06T14:24:16.213 に答える
1

あなたの質問がこれを達成することについてであるかどうかは完全にはわかりませんが、からの動作が必要な場合はshared_ptr、1つから値を解放するshared_ptrと、同じ値への他のすべての共有ポインタがnullptrになる場合は、その振る舞いを達成するためにunique_ptrshared_ptr

void print(std::string name, std::shared_ptr<std::unique_ptr<int>>& ptr)
{
    if(ptr == nullptr || *ptr == nullptr)
    {
        std::cout << name << " points to nullptr" << std::endl;
    }
    else
    {
        std::cout << name << " points to value " << *(*ptr) << std::endl;
    }
}

int main()
{
    std::shared_ptr<std::unique_ptr<int>> original;
    original = std::make_shared<std::unique_ptr<int>>(std::make_unique<int>(50));

    std::shared_ptr<std::unique_ptr<int>> shared_original = original;

    std::shared_ptr<std::unique_ptr<int>> thief = nullptr;

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    thief = std::make_shared<std::unique_ptr<int>>(original->release());

    print(std::string("original"), original);
    print(std::string("shared_original"), shared_original);
    print(std::string("thief"), thief);

    return 0;
}

出力:

original points to value 50
shared_original points to value 50
thief points to nullptr
original points to nullptr
shared_original points to nullptr
thief points to value 50

この動作により、リソース(配列など)を共有し、後でこのリソースへのすべての共有参照を無効にしながら、そのリソースを再利用できます。

于 2017-08-04T15:21:07.760 に答える
0

これがうまくいくかもしれないハックです。あなたが本当の束縛状態にない限り、私はそれをお勧めしません。

template<typename T>
T * release_shared(std::shared_ptr<T> & shared)
{
    static std::vector<std::shared_ptr<T> > graveyard;
    graveyard.push_back(shared);
    shared.reset();
    return graveyard.back().get();
}
于 2011-09-29T22:31:01.697 に答える
0

ポインタが実際に一意である場合、std::unique_ptrまたはboost::scoped_ptr前者がコンパイラで使用できない場合は、を使用してください。それ以外の場合は、との使用を組み合わせることを検討boost::shared_ptrしてboost::weak_ptrください。詳細については、 Boostのドキュメントを確認してください。

于 2013-05-19T10:34:24.867 に答える
0

生のHTTPRequestHandler*を返すことを期待するPoco::HTTPRequestHandlerFactoryを使用していますが、リクエストが終了すると、Pocoフレームワークはハンドラーを削除します。

また、DI Sauceプロジェクトを使用してコントローラーを作成しますが、インジェクターは直接返すことができないshared_ptrを返します。また、この関数が返すとすぐにshared_ptrがスコープ外になり、ハンドラーが削除されるため、handler.get()を返すことも適切ではありません。実行される前に、ここに.release()メソッドがある合理的な(私が思う)理由があります。私は次のようにHTTPRequestHandlerWrapperクラスを作成することになりました:-

class HTTPRequestHandlerWrapper : public HTTPRequestHandler {
private:
    sauce::shared_ptr<HTTPRequestHandler> _handler;

public:
    HTTPRequestHandlerWrapper(sauce::shared_ptr<HTTPRequestHandler> handler) {
        _handler = handler;
    }

    virtual void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) {
        return _handler->handleRequest(request, response);
    }
};

そして工場は

HTTPRequestHandler* HttpHandlerFactory::createRequestHandler(const HTTPServerRequest& request) {
    URI uri = URI(request.getURI());
    auto path = uri.getPath();
    auto method = request.getMethod();

    sauce::shared_ptr<HTTPRequestHandler> handler = _injector->get<HTTPRequestHandler>(method + ":" + path);

    return new HTTPRequestHandlerWrapper(handler);
}

これはソースとポコの両方を満足させ、うまく機能します。

于 2017-03-28T00:50:42.643 に答える
0

非同期ハンドラーを介してポインターを渡し、失敗した場合に自己破壊動作を維持する必要がありましたが、最終的なAPIは生のポインターを期待していたため、この関数を単一のshared_ptrから解放しました。

#include <memory>

template<typename T>
T * release(std::shared_ptr<T> & ptr)
{
    struct { void operator()(T *) {} } NoDelete;
    
    T * t = nullptr;
    if (ptr.use_count() == 1)
    {
        t = ptr.get();
        ptr.template reset<T>(nullptr, NoDelete);
    }
    return t;
}

代わりにptr.use_count() != 1取得する場合。nullptr


cppreference(太字の強調鉱山)から、次のことに注意してください。

1を返す場合use_count、他の所有者はありません。(非推奨のメンバー関数unique()は、このユースケース用に提供されています。)マルチスレッド環境では、以前の共有所有者による管理対象オブジェクトへのアクセスが完了していない可能性があり、新しい共有所有者が完了している可能性があるため、オブジェクトが安全に変更できることを意味しません。によってなど、同時に導入されstd::weak_ptr::lockます。

于 2017-04-14T12:37:47.917 に答える
-1

簡単な解決策、参照を増やしてから、shared_pointerをリークします。

boost::shared_ptr<MyType> shared_pointer_to_instance(new MyType());
new boost::shared_ptr<MyType>();
MyType * raw_pointer = shared_pointer_to_instance.get()

これにより、shared_ptrとMyTypeの両方のメモリリークが明らかに発生します*

于 2016-03-07T10:30:48.883 に答える