正在理解智能指针,但出现错误:未分配正在释放的指针

Understanding smart pointers but error: pointer being freed was not allocated

本文关键字:指针 分配 释放 错误 智能      更新时间:2023-10-16

我正在尝试理解智能指针,并有以下代码:

#include <iostream>
#include <string>
#include <memory>
using namespace std;
struct B 
{
string hello() { return "hello world"; }
};
class A
{
private:
B* a;
public:
A() { a = new B; }
~A() { delete a; a = nullptr; }
B* get() { return a; }
};
int main(int argc, const char * argv[]) {
A a;
shared_ptr<B> p(a.get());
cout << p->hello() << endl;
p.reset();
return 0;
}

我在这里试图做的是访问原始指针,但通过智能指针。它打印"你好世界"很好,当我注释掉A的析构函数时没有错误。然而,当我取消注释它时,我会得到以下错误:

test(9758,0x7fff738d9300) malloc: *** error for object 0x1001053a0: pointer 
being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

这是怎么回事?shared_ptr,p是否在超出作用域或重置(为nullptr(时调用析构函数?p是如何处理由于未删除A::A而导致的内存泄漏的?

我知道智能指针通常处理新对象,这种情况可能不经常使用,但我想尝试学习一下。

当shared_ptr,p超出作用域或重置(为nullptr(时,它是否正在调用析构函数?

没错。

p如何处理不删除A::A导致的内存泄漏?

p认为它拥有该对象,所以它删除了它。没有泄漏。但是a也认为它也拥有这个对象,所以它试图第二次删除它并崩溃。

我知道智能指针通常处理新对象,这种情况可能不经常使用,但我想尝试学习一下。

这是一种根本没有使用的情况,因为正是出于这个原因,不可能让多个对象同时拥有相同的内存。

正确的解决方案是让class A在内部使用shared_ptr

class A {
private:
shared_ptr<B> b;
public:
A() { b.reset(new B); }
shared_ptr<B> get() { return b; }
};
int main(int argc, const char * argv[]) {
A a;
shared_ptr<B> p = a.get();
cout << p->hello() << endl;
p.reset();
return 0;
}

或者干脆不要拥有一个你没有直接分配给自己的原始指针:

int main(int argc, const char * argv[]) {
A a;
B *p = a.get();
cout << p->hello() << endl;
return 0;
}

使用智能指针的全部目的是明确谁拥有什么,以及所有权如何转移。你的例子违反了这一点。

A a;shared_ptr<B> p(a.get());指向内存中相同的已分配B对象。p.reset()销毁该B对象,然后~A()析构函数尝试再次释放它。

来自shared_ptr::reset():

如果*this已经拥有一个对象,并且是最后一个拥有该对象的shared_ptr,则将通过拥有的deleter销毁该对象

您的p.reset((删除了B对象,因为它对拥有它的变量a一无所知,并且您没有手动增加p的引用计数(这在shared_ptr中是不可能的,因为它被设计为只通过复制shared_ptr对象来共享指针(。

你在这里试图用reset(ptr(做的是未定义的行为:

如果ptr指向的对象已经拥有,则函数结果处于未定义的行为。

https://en.cppreference.com/w/cpp/memory/shared_ptr/reset