【问题标题】:Is there any way to check if an std::function points to a member of a valid object?有什么方法可以检查 std::function 是否指向有效对象的成员?
【发布时间】:2014-08-20 16:47:41
【问题描述】:

让我证明我的意思。

#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;
}

这个输出:

number is 0
number is 1

如果我们像往常一样调用函数,将“function()”替换为“obj->printNumber()”,输出为:

number is 0
Segmentation fault: 11

正如你所期望的那样。

所以我的问题是,是否有任何方法可以确保在对象已被释放时我们无法调用该函数?这与使用智能指针无关,它与普通指针的工作方式相同。

【问题讨论】:

标签: c++ c++11 std-function stdbind c++14


【解决方案1】:

您的代码有效。

obj.reset() 不会释放共享的MyClass 对象,因为在绑定表达式function 中存在共享指针obj 的副本。这是因为 std::bind 复制(或移动)它的参数,除非包裹在 reference_wrapper 中(例如通过 std::ref)。

如果您在MyClass 的析构函数上插入或放置断点,您会发现直到main 结束时才调用它,此时局部变量function 被析构。

【讨论】:

  • @whoosy:这证明不了。 UB。没有会员访问权限。任君挑选。
  • @whoosy 在这种情况下,您正在读取和写入释放的内存,这通常具有与间接重置智能指针(或间接nullptr)不同的(仍然未定义!)行为。您会注意到在这种情况下没有分段错误,无论您使用绑定表达式还是直接调用 obj-&gt;printNumber()
【解决方案2】:

有什么方法可以检查std::function points 是否为有效对象的成员?

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

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

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

【讨论】:

  • 在这种情况下,函数确实拥有该对象,因为std::bind复制了它的参数。
  • @ecatmur 你说得对std::bind,我删除了这个注释。
【解决方案3】:

“这与使用智能指针无关,它与常规指针的工作方式相同。” 这种说法是不正确的。带有智能指针的 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 ) );

【讨论】:

    猜你喜欢
    • 2011-01-13
    • 2010-09-30
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    • 2011-09-11
    相关资源
    最近更新 更多