从已释放的指针移动会泄漏内存吗?

Ant*_*Ant 2 c++ smart-pointers move-semantics

我有以下代码:

\n
std::unique_ptr<T> first = Get();\n\xe2\x80\xa6\nT* ptr_to_class_member = GetPtr(obj);\n*ptr_to_class_member = std::move(*first.release());\n
Run Code Online (Sandbox Code Playgroud)\n

这是否会按预期运行,没有副本、1 次移动并且没有内存泄漏?

\n

fab*_*ian 6

*ptr_to_class_member = std::move(*first.release());
Run Code Online (Sandbox Code Playgroud)

只需调用 的 移动赋值运算符,T并将其指向的对象first作为参数。这可能会正确传输一些数据,但delete不会被调用或对象,因此既不会T::~T执行,也不会释放对象的内存。

在这个示例中T = std::string,将导致字符串对象的后备存储正确地从移动分配的右侧转移到左侧,但动态分配的内存大小sizeof(std::string)仍然会泄漏。

对于某些类,缺少对象的析构函数调用可能会导致额外的麻烦,因为移动分配只需要使 rhs 处于未指定但有效的状态,这可能仍然需要释放额外的资源。

你需要做

*ptr_to_class_member = std::move(*first);
first.reset();
Run Code Online (Sandbox Code Playgroud)

以防止内存泄漏。


为了显示这里出了什么问题,以下代码实现了内存(取消)分配和特殊成员函数的打印:

#include <iostream>
#include <memory>
#include <new>
#include <utility>


struct TestObject
{
    TestObject()
    {
        std::cout << "TestObject::TestObject() : " << this << '\n';
    }

    TestObject(TestObject&& other)
    {
        std::cout << "TestObject::TestObject(TestObject&&) : " << this << ", " << &other << '\n';
    }

    TestObject& operator=(TestObject&& other)
    {
        std::cout << "TestObject::operator=(TestObject&&) : " << this << ", " << &other << '\n';
        return *this;
    }

    ~TestObject()
    {
        std::cout << "TestObject::~TestObject() : " << this << '\n';
    }

    void* operator new(size_t size)
    {
        void* const result =  ::operator new(size);
        std::cout << "memory allocated for TestObject: " << result << '\n';
        return result;
    }

    void operator delete(void* mem)
    {
        std::cout << "memory of TestObject deallocated: " << mem << '\n';
        ::operator delete(mem);
    }
};


template<class Free>
void Test(Free free, char const* testName)
{
    std::cout << testName << " begin -------------------------------------------\n";

    {
        auto ptr = std::make_unique<TestObject>();
        std::cout << "object creation done\n";
        free(ptr);
    }

    std::cout << testName << " end ---------------------------------------------\n";
}

int main()
{
    TestObject lhs;

    Test([&lhs](std::unique_ptr<TestObject>& ptr)
        {
            lhs = std::move(*ptr);
            ptr.reset();
        }, "good");
    Test([&lhs](std::unique_ptr<TestObject>& ptr)
        {
            lhs = std::move(*ptr.release());
        }, "bad");

}
Run Code Online (Sandbox Code Playgroud)

可能的输出:

TestObject::TestObject() : 0000009857AFF994
good begin -------------------------------------------
memory allocated for TestObject: 000001C1D5715EF0
TestObject::TestObject() : 000001C1D5715EF0
object creation done
TestObject::operator=(TestObject&&) : 0000009857AFF994, 000001C1D5715EF0
TestObject::~TestObject() : 000001C1D5715EF0
memory of TestObject deallocated: 000001C1D5715EF0
good end ---------------------------------------------
bad begin -------------------------------------------
memory allocated for TestObject: 000001C1D5715EF0
TestObject::TestObject() : 000001C1D5715EF0
object creation done
TestObject::operator=(TestObject&&) : 0000009857AFF994, 000001C1D5715EF0
bad end ---------------------------------------------
TestObject::~TestObject() : 0000009857AFF994
Run Code Online (Sandbox Code Playgroud)

您可以清楚地看到第二种情况下缺少析构函数调用和释放,这与您所询问的代码相匹配。