gpt4 book ai didi

c++ - 为什么不能消除 unique_ptr 的死存储?

转载 作者:太空狗 更新时间:2023-10-29 21:32:57 24 4
gpt4 key购买 nike

#include <memory>
#include <vector>
using namespace std;

vector<unique_ptr<int>> e;

void f(unique_ptr<int> u) {
e.emplace_back(move(u));
}

对于ClangGCC ,上面的代码片段生成如下内容:

f(std::unique_ptr<int, std::default_delete<int> >):
mov rsi, QWORD PTR e[rip+8] # rsi: vector.end_ptr
cmp rsi, QWORD PTR e[rip+16] # [e + rip + 16]: vector.storage_end_ptr
je .L52 # Slow path, need to reallocate
mov rax, QWORD PTR [rdi] # rax: unique_ptr<int> u
add rsi, 8 # end_ptr += 8
mov QWORD PTR [rdi], 0 # <==== Do we need to set the argument u to null here?
mov QWORD PTR [rsi-8], rax # *(end_ptr - 8) = u
mov QWORD PTR e[rip+8], rsi # update end_ptr
ret
.L52: # omitted

我想知道为什么编译器会在这个函数中生成mov QWORD PTR[rdi], 0?是否有任何约定要求编译器这样做?

此外,对于更简单的情况,如 this :

void f(unique_ptr<int> u);

void h(int x) {
auto p = make_unique<int>(x);
f(move(p));
}

为什么编译器会生成:

call    operator delete(void*, unsigned long)

h() 的末尾,假设在调用 f 之后 p 总是 nullptr?

最佳答案

在这两种情况下,答案都是:因为你移动的对象仍然会被销毁。

如果您查看为调用生成的代码

void f(unique_ptr<int> u);

您会注意到调用者为参数 u 创建对象,然后按照调用约定的要求调用其析构函数。如果对 f() 的调用是内联的,编译器很可能能够优化它。但是为 f() 生成的代码无法控制 u 的析构函数,因此必须将 u 的内部指针设置为零假设 u 的析构函数将在函数返回后运行。

在你的第二个例子中,我们有一种相反的情况:

void h(int x) {
auto p = make_unique<int>(x);
f(move(p));
}

与名称可能暗示的相反,std::move() 实际上并不移动对象。它所做的只是转换为一个右值引用,该引用允许该引用的接收者从所引用的对象中移动——如果他愿意的话。实际移动只会发生,例如,当另一个对象通过移动构造函数从给定参数构造时。由于编译器对 h() 定义点处的 f() 内部发生的事情一无所知,因此它不能假设 f() 将始终从给定对象移动。例如,f() 可以仅在某些情况下简单地返回或移动,而在其他情况下则不能。因此,编译器必须假定该函数可能会在不从对象移动的情况下返回,并且必须为析构函数发出 delete。该函数还可以执行移动赋值而不是移动构造,在这种情况下,仍然需要外部析构函数来释放之前由新对象分配的所有权所持有的对象的所有权……

关于c++ - 为什么不能消除 unique_ptr 的死存储?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53330428/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com