-2

shared_ptr を 1 つずつ破棄しようとしていますが、最後のポインターを破棄すると、use_count() が異常になります。私のコードを観察してください:

#include <iostream>
#include <memory>


int main() {

    int * val = new int(5);
    std::shared_ptr<int> myPtr = std::make_shared<int>(*val);

    myPtr.~__shared_ptr();

}

デバッガーで次の出力が生成されます。

myPtr value: 5  myPtr.use_count():8787448 // Or some other large int

最終的な破壊で use_count() を 0 に設定し、整数のメモリの割り当てを解除することを期待していました。これは何も起こっていないようです。

use_count() == 1 の場合に if() ステートメントを使用できますが、これは非常に洗練されていないようです。誰かが別の解決策を知っていますか?

4

2 に答える 2

2

私はあなたが何を求めているのか理解したと思います。共有オブジェクトの使用回数がゼロになったことを検出したいとします。

これを行う方法は、std::shared_ptrで動作するように設計されたstd::weak_ptrを使用することで、オブジェクトが破棄されたかどうかを追跡できます。

ここ:

#include <memory>
#include <iomanip>
#include <iostream>

int main()
{
    // weak_ptr is only convertable to a shared_ptr if the shared_ptr
    // usage count is > 0
    std::weak_ptr<int> wp;

    {
        std::shared_ptr<int> ptr = std::make_shared<int>(5);
        wp = ptr; // link weak_ptr to shared_ptr

        if(auto sp = wp.lock()) // try to convert weak_ptr to shared_ptr
        {
            // if we get here use_count was > 0
            std::cout << "Before: use count > 0: "
                << std::boolalpha << (sp.use_count() > 0) << '\n';
        }
        else
        {
            // if we get here use_count was == 0
            std::cout << "Before: Destroyed\n";
        }
        // ptr goes out of scope here
    }

    if(auto sp = wp.lock()) // try to convert weak_ptr to shared_ptr
    {
        // if we get here use_count was > 0
        std::cout << "After: use count > 0: "
            << std::boolalpha << (sp.use_count() > 0) << '\n';
    }
    else
    {
        // if we get here use_count was == 0
        std::cout << "After: Destroyed\n";
    }
}

基本的に、リンクされたstd::shared_ptrがまだオブジェクトへの参照を保持している場合、関連する std::weak_ptrはstd::weak_ptr::lockを使用してstd::shared_ptrに変換できます。それが失敗した場合、関連するstd::shared_ptrはもはや共有オブジェクトを指していません - 破棄されています。

于 2015-10-04T01:21:01.597 に答える
2

shared_ptr を 1 つずつ破棄しようとしていますが、

それが何を意味するのかわかりませんが、...

myPtr.~__shared_ptr();

決して、決して、これをしないでください。

自動オブジェクト、つまりスタック上に存在し、スコープ外になるとコンパイラによって自動的に破棄されるオブジェクトのデストラクタを実行しています。手動で破壊すると、2 回破壊されます。オブジェクトの寿命を 2 回終わらせることはできません。それはジェームズ ボンドではなく、一度だけ生きます。

同じオブジェクトを 2 回破棄することは未定義の動作です。つまり、奇妙なことが起こり得るということです。未定義の動作をするプログラムから奇妙な結果が得られる理由を尋ねるのは、時間の無駄です。未定義の動作があるため、未定義の動作があると奇妙なことが起こります。何でも起れる。奇妙であり、壊滅的ではないことに感謝する必要があります。

標準は、12.4 [class.dtor] では、この正確なシナリオが未定義の動作であることを明確に指摘しています。

オブジェクトに対してデストラクタが呼び出されると、そのオブジェクトは存在しなくなります。有効期間が終了したオブジェクトに対してデストラクタが呼び出された場合の動作は未定義です (3.8)。[例:自動オブジェクトのデストラクタが明示的に呼び出され、その後、通常はオブジェクトの暗黙的な破棄を呼び出す方法でブロックが残される場合、動作は未定義です。— 最後の例]

さらに悪いことに、の基本クラスのデストラクタを実行しているため、オブジェクトの一部myPtrのみを破棄しています。つまり、一部が死んで一部が生きているオブジェクトがあり、スコープの終わりにその一部が再び殺されます。いかなる状況においても、それが正しいとは限りません。これまで。

最終的な破壊で use_count() を 0 に設定し、整数のメモリの割り当てを解除することを期待していました。これは何も起こっていないようです。

あなたの結論は間違っています。おそらく起こっているのですが、オブジェクトが破棄されてメモリの割り当てが解除された場合、それを調べようとすると意味のない結果が生じます。ゾンビに名前を尋ねることはできません。ゾンビは「BRAINZZZZ!」と答えます。役に立つことを伝える代わりに。そして、あなたの脳を食べます。今、あなたは死んでいます。ゾンビで遊んではいけません。

また、Neil Kirk が上でコメントしているように、これも間違っています。

int * val = new int(5);
std::shared_ptr<int> myPtr = std::make_shared<int>(*val);

ヒープ上に を作成し、 によって管理されるヒープ上にそのコピーintを作成します。は同じ値を持つan を所有していますが、何も所有していないため、メモリリークが発生します。おそらく、次のいずれかを行うつもりでした。shared_ptrshared_ptrint*valval

int * val = new int(5);
std::shared_ptr<int> myPtr(val);

またはおそらくこれ:

int val = 5;
std::shared_ptr<int> myPtr = std::make_shared<int>(val);
于 2015-10-04T01:15:21.297 に答える