0

Let me demonstrate what I mean.

#include <functional>
#include <iostream>

class MyClass
{
private:
    int number;
public:
    MyClass()
    {
        number = 0;
    }

    void printNumber()
    {
        std::cout << "number is " << number << std::endl;
        number++;
    }
};

int main()
{
    std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
    auto function = std::bind(&MyClass::printNumber, obj);

    function();

    // This deallocates the smart pointer.
    obj.reset();

    // This shouldn't work, since the object does not exist anymore.
    function();

    return 0;
}

This outputs:

number is 0
number is 1

If we were to call the function like we would normally, replacing "function()" with "obj->printNumber()", the output is:

number is 0
Segmentation fault: 11

Just like you would expect it to be.

So my question is if there is any way to make sure that we are unable to call the function when the object has been deallocated? This has nothing to do with using smart pointers, it works the same way with regular pointers.

4

3 回答 3

6

您的代码有效。

obj.reset()不会释放共享对象,因为在 bind-expression 中存在MyClass共享指针的副本。这是因为复制(或移动)它的参数,除非包裹在(例如 by )中。objfunctionstd::bindreference_wrapperstd::ref

如果您在 的析构函数上检测或放置断点MyClass,您会发现直到main局部变量function被破坏时才调用它。

于 2014-08-20T17:00:10.370 回答
3

有没有办法检查std::function points一个有效对象的成员是否存在?

std::function不指向“对象的成员”,它封装了一个Callable。当你将它与一个对象绑定时,你会得到另一个可调用对象(实际上是未指定类型),它可以存储在一个std::function

所以我的问题是,是否有任何方法可以确保在对象已被释放时我们无法调用该函数?

不,没有办法。但正如 ecatmur 所指出的,由于std::bind复制了它的参数,所以在你的例子中你很好。

于 2014-08-20T17:07:13.447 回答
0

“这与使用智能指针无关,它与常规指针的工作方式相同。” 这种说法是不正确的。带有智能指针的 obj->printNumber() 失败不是因为对象被销毁,而是因为共享指针的这个特定实例obj不再指向有效对象。如果您尝试使用原始指针执行此操作:

MyClass *obj = new MyClass;
auto function = std::bind(&MyClass::printNumber, obj);

function();

delete obj;

// This will have UB
function();

在销毁和内存释放之后,您将获得使用对象的完全不同的情况(未定义的行为)。

C++ 中无法验证原始指针是否指向有效对象。但是您可以使用的是std::weak_ptr. 它不能直接使用,std::bind因此您可能需要编写一个 lambda 或一个简单的包装器,您可以在其中检查该对象是否仍然有效:

auto wrapper = []( std::weak_ptr<MyClass> wobj ) { auto obj = wobj.lock(); if( obj ) obj->printNumber(); };
auto function = std::bind( wrapper, std::weak_ptr<MyClass>( obj ) );
于 2014-08-20T17:24:47.407 回答