-2

我试图一个接一个地破坏一个 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 并为整数释放内存。似乎这一切都没有发生。

当 use_count() == 1 时,我可以 if() 声明这个,但这似乎很不雅。有谁知道另一种解决方案?

4

2 回答 2

2

我正在尝试一个一个地破坏 shared_ptr,

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

myPtr.~__shared_ptr();

永远,永远,永远这样做。

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

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

该标准在 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在堆上创建一个,然后在堆上创建它的副本,该副本将由一个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);
于 2015-10-04T01:15:21.297 回答
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仍然持有对该对象的引用,则关联的 std::weak_ptr可以使用std::weak_ptr::lock转换为std::shared_ptr。如果失败,则关联的std::shared_ptr不再指向共享对象 - 它已被销毁。

于 2015-10-04T01:21:01.597 回答