使用unique_ptr的reset方法触发free(): invalid pointer错误,make_unique则正常的问题咨询
嘿,咱们来拆解下你遇到的这个问题,核心是unique_ptr的管理规则和你传入的指针类型不匹配导致的,先看你的完整代码:
#include <iostream> #include <memory> #include <string> using namespace std; int main() { unique_ptr<string> p= nullptr; auto l=[&p]()->void{ static string x {"1111"}; cout<<x<<endl; //p = std::make_unique<string>(x);// compile ok p.reset(&x);//compile error free():invalid pointer; cout<<p.get()<<endl; return; }; l(); cout<<p->length()<<endl; cout<<p.get()<<endl; return 0; }
问题根源分析
先对比两种写法的本质差异:
std::make_unique<string>(x)为什么正常?
这个函数会在堆内存上新建一个string对象,把静态变量x的值拷贝到这个新对象里,然后让unique_ptr接管这个堆对象的所有权。unique_ptr的默认删除器是用delete释放内存,而堆内存正是通过new分配的,完全符合它的管理规则,所以销毁时不会出问题。p.reset(&x)为什么触发错误?
你传给reset的是静态变量x的地址,x是static修饰的局部变量,它存储在静态存储区,根本不是通过new动态分配的堆内存。而unique_ptr的默认行为是在生命周期结束时调用delete来释放它管理的指针,但delete只能用于释放new分配的堆内存,对静态存储的对象执行delete是完全非法的未定义行为,这就是你看到free(): invalid pointer错误的直接原因。
关于你的猜想的补充
你提到“离开作用域时析构函数被调用两次”,其实准确的逻辑是:
静态变量x的生命周期是整个程序,程序结束时它会被自动销毁(这是正常行为);而unique_ptr在main函数结束时销毁,会尝试用delete释放x的地址,这相当于对同一个静态对象执行了一次非法的内存释放操作,并不是析构函数被调用两次,但这个非法操作已经足够触发内存错误了。
怎么解决?
如果确实需要让unique_ptr管理这个静态对象,你需要给它指定一个空删除器,告诉它不需要释放内存:
p.reset(&x, [](string*){}); // 自定义删除器,什么都不做
不过更建议的方式是:静态变量本身不需要智能指针来管理,直接使用即可,unique_ptr的设计初衷就是用来管理动态分配的堆内存,别让它越界干活~
备注:内容来源于stack exchange,提问作者Paoer111

