Unique_ptr:在列表中放置时未分配释放的指针

Unique_ptr: pointer being freed was not allocated when emplaced in list

本文关键字:分配 释放 指针 ptr 列表 Unique      更新时间:2023-10-16

我有一个简单的C++程序,如下所示:

#include <iostream>
#include <list>
#include <memory>
int main(void) {
std::list<std::unique_ptr<int>> l;
int x = 5;
// throws runtime error: pointer being freed was not allocated
l.emplace_back(&x);
}

当程序运行时,我获得以下输出:

a.out(59842,0x7fffb13d1380) malloc: *** error for object 0x7ffee81489ac: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug [1] 59842 abort ./a.out

这告诉我,在列表的销毁过程中,已经创建的unique_ptr对象将被销毁,而在销毁过程中指向x的指针将被释放,而它从来都不是malloc

然而,我预计在unique_ptr超出范围并且是destroyed:的情况下也会发生同样的情况

#include <iostream>
#include <list>
#include <memory>
int main(void) {
int x = 5;
// does not throw runtime error when falling out of scope and being destructed
std::unique_ptr<int> p(&x);
}

然而,当上面的unique_ptr p超出范围并被销毁时,程序运行良好。为什么第一个程序在销毁unique_ptr时给我一个错误,而第二个程序没有?为什么在列表中放置unique_ptr会导致其销毁失败?

未定义的行为可能会导致任何事情,从崩溃到明显成功的竞选,再到英国投票退出欧盟(哇,对不起,伙计们…空指针取消引用的作用真是太神奇了(。

编译器是极其复杂的东西。您的程序不是目标计算机将按顺序执行的指令的一对一映射;它大致描述了您希望计算机的行为。两者之间的转换是高度深奥和复杂的。当你偏离轨道时,你会破坏语言,使编译器的内部工作方式—他们不断做出假设,走自己知道可以走的捷径,尤其是在应用所谓的"优化"时;以不可预测的方式破碎。

这是其中之一。

简而言之,如果期望UB做任何特别的事情,那么您已经失败了。

通过分析编译器的源代码和生成的程序集,可以准确地确定UB在这种情况下的行为原因。但这将是一个漫长、艰巨且最终毫无意义的过程。

只是不要用你没有动态分配的东西来制作智能指针(或者,如果你出于某种原因真的想,提供一个自定义的deleter,它不会尝试delete,而不是newd(。易于理解的

我认为第二个例子中的变量p只是经过了优化,因此没有导致运行时错误。

但发生的错误是显而易见的,它试图释放在堆栈上分配的内存。请注意,智能指针通常与堆分配内存一起使用,而不是与堆栈上分配的内存一起使用。

我已经复制并编译了您的代码:

$ g++ omg.cpp && ./a.exe
Aborted (core dumped)

您可以尝试添加另一个间接级别:

int main(void) {
int x = 5;
{
std::unique_ptr<int> p(&x);
}
}

看看它是否有帮助。