逐一销毁单个 shared_ptr

Destructing a Single shared_ptr One-by-One

我试图一个接一个地销毁 shared_ptr,但是当我销毁最后一个指针时,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 并为整数释放内存。这似乎 none 正在发生。

我可以在 use_count() == 1 时使用 if() 语句,但这看起来很不雅。有谁知道另一种解决方案?

I am attempting to destruct a shared_ptr one-by-one,

我不知道那是什么意思,但是...

myPtr.~__shared_ptr();

永远,永远,永远不要这样做。

您是 运行 自动对象的析构函数,即存在于堆栈中并在超出范围时由编译器自动销毁的对象。通过手动销毁它,您会导致它被销毁两次。你不能结束一个对象的生命两次,它不是詹姆斯·邦德,它只有一次。

两次销毁同一个对象是未定义的行为。这意味着可能会发生奇怪的事情。询问为什么从具有未定义行为的程序中得到奇怪的结果是浪费时间。当你有未定义的行为时会发生奇怪的事情因为你有未定义的行为。任何事情都可能发生。你应该庆幸这只是奇怪,而不是灾难性的。

该标准在 12.4 [class.dtor]:

中明确指出这种情况是未定义的行为

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (3.8). [Example: if the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined. — end example]

更糟糕的是,你是 运行 myPtr 的基础 class 的析构函数,所以你只破坏了对象的 部分 .这意味着你有一个对象,其中一部分是死的,一部分是活的,然后在作用域结束时,它的一部分再次被杀死。在任何情况下,这都不是正确的做法。曾经。

I was hoping on the final destruction it would set the use_count() to 0 and deallocate the memory for the integer. It appears none of this is happening.

你的结论是错误的。它可能正在发生,但如果对象被销毁并且内存被释放,那么试图查看它会产生无意义的结果。你不能问僵尸它的名字是什么,它会回答 "BRAINZZZZ!" 而不是告诉你任何有用的东西。并吃掉你的大脑。现在你死了。不要玩丧尸

此外,正如 Neil Kirk 上面评论的那样,这也是错误的:

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

您在堆上创建一个 int,然后在将由 shared_ptr 管理的堆上创建它的 副本shared_ptr 拥有一个 int,它与 *val 具有相同的值,但没有任何东西拥有 val,因此这将是内存泄漏。您可能打算这样做:

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

或更可能是:

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

我想我明白你想要什么了。您想检测共享对象的使用计数何时为零。

这样做的方法是使用 std::weak_ptr that is designed to work with the std::shared_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 still holds a reference to the object then the associated std::weak_ptr can be converted to a std::shared_ptr using std::weak_ptr::lock. If that fails then the associated std::shared_ptr 不再指向共享对象 - 它已被销毁。