为什么即使在分配给该指针的 unique_ptr 超出范围后该指针仍然存在?

Rom*_*huk 1 c++ pointers memory-management smart-pointers unique-ptr

我最近开始学习 C++ 中的智能指针和移动语义。但我不明白为什么这段代码有效。我有这样的代码:

#include <iostream>
#include <memory>

using namespace std;

class Test
{
public:
    Test() 
    {
        cout << "Object created" << endl;
    }

    void testMethod()
    {
        cout << "Object existing" << endl;
    }

    ~Test() 
    {
        cout << "Object destroyed" << endl;
    }
};

int main(int argc, char *argv[])
{
    Test* testPtr = new Test{};
    {
        unique_ptr<Test> testSmartPtr(testPtr);
    }
    testPtr->testMethod();
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我的输出是:

Object created
Object destroyed
Object existing
Run Code Online (Sandbox Code Playgroud)

为什么行testPtr->testMethod()有效?如果指针是左值,unique_ptr 不会在销毁时删除分配给它的指针吗?

编辑:我从评论中了解到,此方法不会检查指针是否存在。如果是这样,有没有办法检查指针是否有效?

编辑:我了解到我不应该对无效指针做任何事情。感谢您的所有回答和评论。

编辑:即使这个代码也有效:

#include <iostream>
#include <memory>

using namespace std;

class Test
{
public:
    Test(int num) :
        number{ num }
    {
        cout << "Object created" << endl;
    }

    void testMethod(int valueToAdd)
    {
        number += valueToAdd;
        cout << "Object current value: " << number << endl;
    }

    ~Test() 
    {
        cout << "Object destroyed" << endl;
    }

private:
    int number;
};

int main(int argc, char *argv[])
{
    Test* testPtr = new Test(42);
    {
        unique_ptr<Test> testSmartPtr(testPtr);
    }
    testPtr->testMethod(3);
    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我认为这是因为编译器优化了它。不管怎样,我真的不应该用无效的指针做任何事情。

for*_*818 6

您不需要std::unique_ptr编写具有相同问题的代码

int main(int argc, char *argv[])
{
    Test* testPtr = new Test{};
    delete testPtr;
    testPtr->testMethod();       // UNDEFINED !!!
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出与您的输出相同https://godbolt.org/z/8bocKGj1M,但它可能完全是其他东西。该代码具有未定义的行为。您不得取消引用无效的指针。

如果您实际上在中使用了该对象的成员testMethod(),则崩溃的可能性更大,但也不能保证。看起来不错是未定义行为的最糟糕的化身。

您的代码很好地说明了为什么您应该new完全禁止 raw。至少您应该new仅作为参数调用智能指针构造函数,或者更好的是,使用std::make_unique. 它基本上只是构造函数调用的包装器new,其主要目的是让您编写不包含以下内容的代码new

int main(int argc, char *argv[])
{
    auto testPtr = std::make_unique<Test>();
    testPtr->testMethod();    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

即使这样,您也可以访问原始指针并执行错误的操作。智能指针有助于所有权,但它们并不是万无一失的。


归档时间:

查看次数:

136 次

最近记录:

3 年,3 月 前