首页 > 解决方案 > 如何成功地将功能对象(或 lambda)传递给轨迹栏回调第二个参数(void*)?

问题描述

我的班级有一个成员函数:

void handler(int pos, cv::Mat &image)
{
    threshold(image, image, pos, 255, CV_THRESH_BINARY);
    cv::imshow("window", this->image); //<-- segfault
}

并且有一个 createTrackbar 的成员回调函数:

static void on_trackbar(int pos, void* ptr);

然后我在另一个成员函数中创建这个函数对象:

std::function<void(int)> bind_handler = std::bind(static_cast<void (my_class::*)(int, cv::Mat&)>(&my_class::handler), this, std::placeholders::_1, img_threshold);
slider = 0;
cv::namedWindow("Test Filter", 1);
cv::createTrackbar("threshold", "Test Filter", &slider, 255, on_trackbar, (void*)&bind_handler);

然后在on_trackbar我抓住了void* ptr

std::function<void(int)>* cb = static_cast<std::function<void(int)>* >(ptr);
(*cb)(pos); //<-- segfault

编译好。

但是当我触摸滑块时,它会出现分段错误:(

我也用 lambdas尝试了这段代码,但它也有段错误。

如果我std::shared_ptr<cv::Mat> thrsh_ptr通过[=]处理lambda,它也会出现段错误。

如何正确制作?

UPD:在处理程序主体中调用。我发现成员函数被回调调用cv::Mat image后,成员变为0x0 。我在正文之前和内部检查它的地址;在这两种情况下,它都是相同的地址值。handleron_trackbarcv::createTrackbarhandler

标签: c++multithreadingopencvc++11

解决方案


正如评论中提到的,bind_handler是一个局部变量,在创建跟踪栏后立即不复存在。当库尝试调用回调时,它会进入您的on_trackbar()函数,传递一个指向现已失效的std::function<>对象的指针,这会在您尝试取消引用它时导致崩溃。该void* ptr参数指向一个不再存在的先前局部变量。

正如@nm 所提到的,您需要做的是将指针传递给包含cv::Mat. 在内部bind_handler(),您将void*参数转换回您的对象类型,并从那里访问图像,调用您希望的任何成员函数。您的问题不够明确,我无法理解您的完整设计,但是是这样的:

class MyClass {
    cv::Mat img_threshold;

    void handler(int pos) {
        cv::threshold(img_threshold, img_threshold, pos, 255, CV_THRESH_BINARY);
        cv::imshow("window", img_threshold);
    }

public:
    static void on_trackbar(int pos, void* ptr) {
        MyClass* obj = reinterpret_cast<MyClass*>(ptr);
        obj->handler(pos);
    }

    void other_function() {
        slider = 0;
        cv::namedWindow("Test Filter", 1);
        cv::createTrackbar("threshold", "Test Filter", &slider, 255, on_trackbar, static_cast<void*>(this));
    }
};

推荐阅读