std::move() 会调用 LHS unique_ptr 所属对象的析构函数吗?

问题描述 投票:0回答:1

考虑以下代码:

#include <memory>
#include <iostream>
#include <string>

// I know this is violationg rule of 5
class ElfData {
    private:
    std::string name;
    public:
    ElfData(std::string aName) : name(aName) {
        std::cout<< name+" Constructor is called\n";
    }
 
   ~ElfData() {
    std::cout<< name+" Destructor is called \n";
   }
};

int main() {

    std::unique_ptr<ElfData> ptr1(new ElfData("Ptr1"));
    std::unique_ptr<ElfData> ptr2(new ElfData("Ptr2"));

    // Will this always call the destructor of object owned by ptr2 ?
    ptr2 = std::move(ptr1);
    return 0;
}

ptr2 = std::move(ptr1)
”行是否总是调用 ptr2 以前拥有的对象的析构函数?如果这是真的,我们可以替换下面的代码吗:

std::unique_ptr<ElfData> ptr1(new ElfData("Ptr1"));
ptr2 = std::move(ptr1);

ptr2.reset(new ElfData("Ptr1"));

?

我尝试在 cpp 参考文档和其他论坛中的类似问题中搜索,但我无法弄清楚这一点。

godbolt 链接:https://godbolt.org/z/Ynja8zaej

c++ smart-pointers unique-ptr stdmove
1个回答
0
投票

为了演示,我扩展了你的例子并添加了一个简单的包装器 围绕 unique_ptr 进行演示:

#include <memory>
#include <iostream>
#include <string>

struct Data {
    std::string name;
    Data(std::string aName) : name(aName) {
        std::cout<< name << " Constructor is called\n";
    }
   ~Data() {
        std::cout<< name << " Destructor is called\n";
   }
};

struct DataPtr{
    std::unique_ptr<Data> ptr;
    DataPtr(Data* data): ptr(data){}
    void operator=(DataPtr&& v){
        std::cout << "unique_ptr to " << ptr->name << " reassigned to " << v.ptr->name << "\n";
        ptr = std::move(v.ptr);
    }
};

int main() {
    DataPtr ptr1(new Data("Data1"));
    DataPtr ptr2(new Data("Data2"));
    ptr2 = std::move(ptr1);
    std::cout<< "End of Scope\n";
    return 0;
}

这会产生以下输出:

Data1 Constructor is called
Data2 Constructor is called
unique_ptr to Data2 reassigned to Data1
Data2 Destructor is called
End of Scope
Data1 Destructor is called

(https://godbolt.org/z/nnK11nfq3)

如您所见,在 ptr2 被重新分配的那一刻, Data2 被破坏, 因为包含它的唯一指针被重新分配了。 (它的移动赋值运算符被调用,它在先前包含的对象上调用

delete
)。 如果你仔细想想什么对象超出了范围,这种行为对你来说应该是有意义的。

值得注意的是,这实际上是移动赋值运算符被调用的结果,not

std::move
,它只是将引用的类型重新解释为右值引用,但没有其他副作用。

© www.soinside.com 2019 - 2024. All rights reserved.