简体   繁体   English

一一销毁单个 shared_ptr

[英]Destructing a Single shared_ptr One-by-One

I am attempting to destruct a shared_ptr one-by-one, yet when I destruct the last pointer, the use_count() goes nuts.我试图一个一个地破坏 shared_ptr,但是当我破坏最后一个指针时, use_count() 变得疯狂。 Observe my code:观察我的代码:

#include <iostream>
#include <memory>


int main() {

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

    myPtr.~__shared_ptr();

}

Will produce the following output in the debugger:将在调试器中产生以下输出:

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

I was hoping on the final destruction it would set the use_count() to 0 and deallocate the memory for the integer.我希望在最终销毁时它将 use_count() 设置为 0 并释放整数的内存。 It appears none of this is happening.似乎这一切都没有发生。

I could if() statement this when the use_count() == 1, but this seems very inelegant.当 use_count() == 1 时,我可以 if() 声明这个,但这看起来很不雅观。 Does anyone know of another solution?有谁知道另一种解决方案?

I am attempting to destruct a shared_ptr one-by-one,我试图一个一个地破坏一个 shared_ptr,

I have no idea what that means, but ...我不知道那是什么意思,但是......

myPtr.~__shared_ptr();

Never, ever, ever do this.永远,永远,永远不要这样做。

You are running the destructor for an automatic object, ie one that lives on the stack and will be destroyed automatically by the compiler when it goes out of scope.您正在为一个自动对象运行析构函数,即一个存在于堆栈中的对象,当它超出范围时将被编译器自动销毁。 By destroying it manually you cause it to be destroyed twice.通过手动销毁它,您会导致它被销毁两次。 You cannot end an object's lifetime twice, it is not James Bond, it only lives once.你不能两次结束一个物体的生命周期,它不是詹姆斯邦德,它只存在一次。

Destroying the same object twice is undefined behaviour.两次销毁同一个对象是未定义的行为。 That means weird things can happen.这意味着可能会发生奇怪的事情。 Asking why you get weird results from a program with undefined behaviour is a waste of time.询问为什么您从具有未定义行为的程序中得到奇怪的结果是浪费时间。 Weird things happen when you have undefined behaviour because you have undefined behaviour .当您有未定义的行为时会发生奇怪的事情,因为您有未定义的行为 Anything can happen.任何事情都可能发生。 You should be thankful it's only weird, and not catastrophic.你应该庆幸这只是奇怪,而不是灾难性的。

The standard specifically points out this exact scenario is undefined behaviour, in 12.4 [class.dtor]:该标准在 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).如果为生命周期已结束 (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] — 结束示例]

Even worse, you are running the destructor for a base class of myPtr so you are only destroying part of the object.更糟糕的是,您正在为myPtr的基类运行析构函数,因此您只是在破坏对象的一部分 That means you have an object where part of it is dead and part of it is alive, and then at the end of the scope part of it gets killed again.这意味着你有一个对象,它的一部分是死的,一部分是活的,然后在作用域结束时它的一部分再次被杀死。 Under no circumstances can that ever be the right thing to do.在任何情况下,这都不是正确的做法。 Ever.曾经。

I was hoping on the final destruction it would set the use_count() to 0 and deallocate the memory for the integer.我希望在最终销毁时它将 use_count() 设置为 0 并释放整数的内存。 It appears none of this is happening.似乎这一切都没有发生。

Your conclusion is wrong.你的结论是错误的。 It probably is happening, but if the object is destroyed and the memory is deallocated then trying to look at it produces nonsense results.它可能正在发生,但是如果对象被销毁并且内存被释放,那么尝试查看它会产生无意义的结果。 You can't ask a zombie what its name is, it will reply "BRAINZZZZ!"你不能问僵尸它的名字是什么,它会回答“BRAINZZZZ!” instead of telling you anything useful.而不是告诉你任何有用的东西。 And eat your brains.并吃掉你的大脑。 Now you are dead.现在你死了。 Don't play with zombies.不要玩僵尸。

Also, as Neil Kirk comments above, this is also wrong:此外,正如 Neil Kirk 上面评论的那样,这也是错误的:

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

You create an int on the heap, then you create copy of it on the heap that will be managed by a shared_ptr .您在堆上创建一个int ,然后在由shared_ptr管理的堆上创建它的副本 The shared_ptr owns an int which has the same value as *val but nothing owns val so that will be a memory leak. shared_ptr拥有一个int ,它与*val具有相同的值,但没有任何东西拥有val因此这将是内存泄漏。 You probably meant to do either this:您可能打算这样做:

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

or more likely this:或更可能是这样:

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

I think I figured out what you are after.我想我知道你在追求什么。 You want to detect when the use count of the shared object is zero.您想检测共享对象的使用计数何时为零。

The way this is done is using a std::weak_ptr that is designed to work with the std::shared_ptr so you can keep track of whether or not the object has been destroyed.这样做的方法是使用std::weak_ptr设计为std::shared_ptr 一起使用,以便您可以跟踪对象是否已被销毁。

Here:这里:

#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";
    }
}

Basically, if the linked 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 .基本上,如果链接的std::shared_ptr仍然持有对对象的引用,那么关联的std::weak_ptr可以使用std::weak_ptr::lock转换为std::shared_ptr If that fails then the associated std::shared_ptr is no longer pointing at the shared object - it has been destroyed.如果失败,则关联的std::shared_ptr不再指向共享对象 - 它已被销毁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM