无法将shared_ptr参数传递给函数指针

问题描述

我对使用带有shared_ptr参数的函数指针的代码有疑问。

这是示例代码

header.h

#include <functional>
#include <iostream>
template <class T> class FuncWrapper{
    private:
        void (*original_function)(T a);
    public:
        void setFunction(void *func);
        void execFunction(T a,void *data);
};

template <class T> void FuncWrapper<T>::setFunction(void *func){
    original_function = (void (*)(T))func;
}

template <class T> void FuncWrapper<T>::execFunction(T a,void *data){   
    FuncWrapper<T>* wrapper = (FuncWrapper<T>*)data;
    std::cout << "inside wrapper " << *(a.get()) << std::endl;
    wrapper->original_function(a);
}

main.cpp

#include <iostream>
#include <memory>
#include "header.h"

class ClassA{
    public:
        ClassA(std::shared_ptr<int> a){
            FuncWrapper<std::shared_ptr<int>> *fw;
            fw = new FuncWrapper<std::shared_ptr<int>>;
            fw->setFunction((void*)&ClassA::print_int);
            std::function<void(std::shared_ptr<int>)> g = std::bind(&FuncWrapper<std::shared_ptr<int>>::execFunction,fw,std::placeholders::_1,fw);
            g(a);
            delete fw;
        }
    private:
        void print_int(std::shared_ptr<int> x) {
            std::cout << "printing int" << std::endl;
            std::cout << "given int " << *(x.get()) << std::endl;
        }
};

int main(int argc,char * argv[]){
    std::shared_ptr<int> x = std::make_shared<int>(10);
    std::cout << "inside main " << *(x.get()) << std::endl;
    ClassA *temp;
    temp = new ClassA(x);
    delete temp;
    return 0;
}

结果

inside main 10
inside wrapper 10
printing int
Segmentation fault (core dumped)

我不知道为什么会导致细分错误

std::shared_ptr<int>更改为int很好。
因此,我认为这与shared_ptr的所有权有关,但是我对智能指针并不熟悉,我完全不知所措。

我想知道

  • 为什么不起作用
  • 如何使其发挥作用

限制是

  • 不更改print_int函数本身
  • FuncWrapper<T>::execFunction内执行函数
  • FuncWrapper<T>::execFunction必须是静态的

否则,可以自由更改。 (在ClassA构造函数内部,在main execFunction内部等等)

解决方法

问题不是shared_ptr,而是函数指针和成员函数的指针不匹配。

您的函数包装器需要一个指向函数(void (*)(std::shared_ptr<int>))的指针,但是您提供了一个指向成员函数(void (ClassA::*)(std::shared_ptr<int>))的指针,这是不同的。一个指向该指针的隐式前导参数被添加到其中。

这是真正的样子:

// pointer to member function
void (*)(ClassA *ptr,std::shared_ptr<int>)

您的shared_ptr转到第一个参数,幸运的是,应用程序出现了段错误。

解决方案之一是使函数print_int静态。

class ClassA{
    public:
        ClassA(std::shared_ptr<int> a){
            FuncWrapper<std::shared_ptr<int>> *fw;
            fw = new FuncWrapper<std::shared_ptr<int>>;
            fw->setFunction((void*)&ClassA::print_int);
            std::function<void(std::shared_ptr<int>)> g = std::bind(&FuncWrapper<std::shared_ptr<int>>::execFunction,fw,std::placeholders::_1,fw);
            g(a);
            delete fw;
        }

    private:
        static void print_int(std::shared_ptr<int> x) {
            std::cout << "printing int" << std::endl;
            std::cout << "given int " << *(x.get()) << std::endl;
        }
};

但是您的代码中似乎还有另一个问题。函数指针不应转换为对象指针(void *是)。也许可以这样改变您的setFunction:

void setFunction(void (*func)(T)) {
        original_function = func;
}

有关here

的更多信息