逐个破坏单个shared_ptr

时间:2015-10-04 00:15:48

标签: c++ pointers shared-ptr smart-pointers explicit-destructor-call

我试图逐个破坏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并释放整数的内存。似乎没有发生这种情况。

我可以if()在use_count()== 1时声明这个,但这看起来非常不优雅。有谁知道另一种解决方案?

2 个答案:

答案 0 :(得分:2)

  

我试图逐个破坏shared_ptr,

我不知道这意味着什么,但是......

myPtr.~__shared_ptr();

从来没有,永远这样做。

您正在运行自动对象的析构函数,即存在于堆栈中的析构函数,当编译器超出作用域时,它将被编译器自动销毁。通过手动销毁它会导致它被销毁两次。你不能两次结束一个物体的生命,它不是詹姆斯邦德,它只存在一次。

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

该标准明确指出这个确切的场景是未定义的行为,在12.4 [class.dtor]中:

  

为对象调用析构函数后,该对象不再存在;如果是,行为是不确定的   为生命周期结束的对象调用析构函数(3.8)。 [例如:如果是析构函数的话   显式调用自动对象,随后以通常的方式保留该块   调用对象的隐式销毁,行为未定义。 - 结束示例]

更糟糕的是,您正在为myPtr的基类运行析构函数,因此您只会销毁该对象的 part 。这意味着你有一个对象,其中一部分已经死亡,其中一部分是活着的,然后在范围的一部分,它再次被杀死。在任何情况下,这都不是正确的做法。如初。

  

我希望最终的破坏它会将use_count()设置为0并释放整数的内存。似乎没有发生这种情况。

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

另外,正如Neil Kirk上面所说,这也是错误的:

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

您在堆上创建int,然后在堆上创建 copy ,它将由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);

答案 1 :(得分:2)

我想我知道你在追求什么。您想要检测共享对象的使用计数何时为零。

完成此操作的方法是使用std::weak_ptr设计用于 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仍然保留对该对象的引用,则可以使用{{3}将关联的 std::weak_ptr转换为std::shared_ptr }。如果失败则关联的 std::weak_ptr::lock不再指向共享对象 - 它已被销毁。