c++ - 容器对象作为 (void*) 传递时的共享指针行为

标签 c++ c++11 memory-management shared-ptr void-pointers

我的类对象 (ObjA) 中有 shared_ptr 变量。要求将此对象存储为另一个类对象 (ObjB) 的 (void*) 实体。

我的问题是,shared_ptr 的行为是什么(关联的堆内存会被释放吗?它的引用计数会怎样?)-

  1. 当ObjA转换为void*时

  2. 当 ObjB 的 void* 实体被转换回 (ClassA *) 时

简化代码:

Class AA{

    shared_ptr<int> aptr;

    public:
        AA(){
            aptr = make_shared<int>(100);
        }
        shared_ptr<int> get_aptr(){
            return aptr;
        }
};


Class BB{

    void *smpl;

    public:

        void setter(void* p){
            smpl = p;
        }

        void* getter(){
            return smpl;
        }
};

int main(){

    AA *objA = new AA();
    BB *objB = new BB();

    objB->setter(objA);
    //status of allocated int in class AA here?

    //some code later
    AA *objA_2 = (AA*)objB->getter();
    //status of allocated int in class AA here?

    shared_ptr<int> p2 = objA_2->get_aptr();
    //is this allowed

}

我最关心的是 - 如何释放 shared_ptr 的内存。 (鉴于它包含在 void* 对象中,无法删除 - shared_ptr 始终保留在范围内) 我试图删除 objB,并在析构函数中对其组件 void* 进行适当的转换-

BB::~BB(){
    delete (*AA)smpl;
}

但这会产生错误,因为 AA 类中的 shared_ptr 变量不允许显式删除 - 它仅在超出范围时释放其分配的区域。 (在这种情况下,它永远不知道什么时候超出范围!)

此外,类 BB 是第三方类 - 我无法修改 smpl 成员变量(节点类中的 _userData 变量,Cocos2dx 中的 _userData 变量)的类型 void*。 请帮助解决此内存泄漏..

最佳答案

void *这里充当一个观察指针。它根本不会影响共享指针,因为共享指针甚至不知道指向其包含对象的原始指针的存在。

如果您选择 shared_ptr<void>,情况会有所不同而不是原始指针(并通过原始共享指针构造它,即您的 setter 应该替换为例如 void setter(std::shared_ptr<void> const& p))。

在这种情况下,引用计数会受到影响,指向的对象的生存将得到保证。关于此选项,请参阅 here .


编辑:从您的评论来看,您似乎正在寻找类似于以下内容的设置:

struct AA
{
    //...
};


struct BB
{
    std::shared_ptr<void> smpl;

    void setter(std::shared_ptr<void> const& p)
    {
        smpl = p;  //now the ref count of your shared_tr to AA is increased
    }
};

int main()
{    
    auto objA = std::make_shared<AA>();
    auto objB = std::make_shared<BB>();

    objB->setter(objA);

    std::cout<<objA.use_count()<<std::endl;   //prints "2"
}

DEMO

调用setter后的引用计数为2 . shared_ptr<void>就像一个普通的共享指针一样,它保留了 AA -object alive,或者如果指针超出范围(并且它本身是指向给定 AA 的最后一个对象),则正确销毁它的对象。

这行得通,因为原始共享指针的删除器已被复制,知道由谁进行销毁。


EDIT2:回答 OP 代码中的问题:

objB->setter(objA);
//status of allocated int in class AA here?

内部的共享指针 AA完全不受影响。

//some code later
AA *objA_2 = (AA*)objB->getter();
//status of allocated int in class AA here?

同样,共享指针不受影响。然而,这一步需要小心:如果原始对象不再存在,您将得到一个悬挂指针。因此,最好使用共享指针。

shared_ptr<int> p2 = objA_2->get_aptr();
//is this allowed

当然,如果指针有效。

我不明白的一件事是为什么您在类内部使用智能指针,而在外部使用原始指针。这是有原因的吗?

关于c++ - 容器对象作为 (void*) 传递时的共享指针行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30527790/

相关文章:

c++ - 谷歌测试宏

c# - 无需安装的 C++ 数据库访问

c++ - 为什么以下代码不会导致 move 对象而不是复制?

c++ - 一个类只能继承一次

C++堆栈实现,不在函数中保留内存

delphi - 我需要释放动态创建的表单吗?

c++ - 没有 QMainWindow 无法录制音频

c++ - 采用函数模板参数的类模板,这些函数模板参数对正在定义的类的实例进行操作

c++ - 为什么 VC++ 编译代码而 clang 不编译?

go - 使用add运算符连接字符串时,Go变量会逸出到堆中