如果 C++ 对象的一个成员函数有一个未完成的 shared_ptr,是否会调用它的析构函数?

问题描述 投票:0回答:3

假设我们有以下课程:

Class MyClass
{
    void func();
    std::shared_ptr<std::function<void()>> getFuncPointer(); // returns pointer to func()
};

假设有一个其他类的对象(我们称它为

objectB
),它拥有一个
shared_ptr
到一个
objectA
类型的对象(
MyClass
)。假设
objectB
objectA
的唯一所有者/用户,并且没有其他人可以访问
objectA
.

以下顺序会发生什么:

  1. objectB
    调用
    objectA->getFuncPointer()
    并存储返回的
    shared_ptr
    .
  2. objectB
    来电
    objectA.reset()

问题:

objectA
的析构函数被调用了吗?

如果

objectB
没有
shared_ptr
objectA
的方法之一,答案显然是肯定的。

我不确定的是

objectB
获得
shared_ptr
objectA
方法之一的影响。

如果答案是YES

如果

objectA
被破坏,但另一个线程通过函数指针仍在
func()
中,那么如果我们访问成员变量会发生什么?似乎有问题,因为
objectA
与其成员一起消失了。

如果答案是NO

似乎有问题,因为我看不到成员函数的

shared_ptr
如何可能使整个对象保持活动状态。函数指针对包含的对象一无所知,对吧?

这两种情况似乎都有问题,所以这就是为什么我不确定哪个是正确答案。

c++ memory memory-management shared-ptr destruction
3个回答
1
投票

成员函数/方法通常在编译器中实现为全局函数,并带有一个额外的第一个参数来接收对象的实例,因此

std::function <void()>
的类型在引用方法函数时实际上是
void (MyClass&)
/
void (MyClass*)
MyClass
[这就是为什么当您尝试为成员函数创建
std::bind
时,您也将对象实例作为第一个参数传入]。

通过返回

shared_ptr
std::function<void()>
,您基本上是在为 &MyClass::func() 构造一个包含
shared_ptr
std::function<void(this)>
,它对实例没有实际所有权,所以答案是 YES
shared_ptr
不应阻止对象的破坏。

编辑: 刚看到你的其他评论,正如我所说的,这些方法就像其他自由函数一样是函数,它们位于进程内存的 CODE 部分,它们不占用 DATA 内存,因此它们与对象的生命周期无关,无论您创建 1 个

MyClass
对象还是 10000 个
MyClass
对象,它们的单个副本(在每个翻译单元的正常情况下)都会存在,因此它们在程序的整个运行时都是可调用的


0
投票

答案是肯定的:一个对象可以而且将会被删除,即使有一个

std::shared_ptr
间接依赖它。通过为给定对象(在本例中为函数)创建
std::shared_ptr
,只要该对象具有共享所有者,您就可以保留该对象,因此您必须保证该对象在该时间内有效。如果你违背诺言,事情就会出错。

这与拥有一个指向对象O2的对象O1并没有什么不同,然后

delete
-ing O2O1还在附近。即使 O1 本身通过
std::shared_ptr
持有,也不会保留 O2.

这两种情况似乎都有问题,所以这就是为什么我不确定哪个是正确答案。

与许多语言不同,C++ 不尝试“安全”。编写调用未定义行为的代码非常容易;使用 C++ 工作的一个重要部分是避免这样做。

std::shared_ptr
help 你写safe 代码的工具,但它不会stop 你写unsafe 代码。


0
投票

很可能是的,它被删除了。对象 A 有一种可能的方法可以通过

getFuncPointer
到 B 来延长它自己的生命周期。那就是如果 getFuncPointer 返回的 std::function 正在捕获实例本身。

使用 enable_shared_from_this 考虑这个实现

class MyClass : public std::enable_shared_from_this<MyClass>
{
public:
    void func();

    std::shared_ptr<std::function<void()>> getFuncPointer()
    {
        auto spThis = shared_from_this(); // get a shared_ptr to "this"

        auto fn = [spThis]() {
            spThis->func();
        };

        auto result = std::make_shared<std::function<void()>>();
        *result = fn;
        return result;
    }
};


那么如果你有这个实现

    auto a = std::make_shared<MyClass>();
    auto spFunc = a->getFuncPointer();
    a.reset();
    (*spFunc)();
    return 0;

上面的

a.reset()
调用会将 shared_ptr 的引用计数减 1,但在 spFunc 中仍然捕获了另一个未完成的引用。当
a
超出范围并释放其捕获的变量时,对象
spFunc
最终将被删除。

© www.soinside.com 2019 - 2024. All rights reserved.