将成员函数 ptr 插入地图

Posted

技术标签:

【中文标题】将成员函数 ptr 插入地图【英文标题】:inserting member function ptr into a map 【发布时间】:2019-10-24 14:24:51 【问题描述】:

EDIT从代码本身中删除格式(粗体)。

Edit 2在答案末尾添加了修复

我有以下代码,我正在尝试创建静态多态性和模板类, 我正在尝试将只有一个派生类型成员函数ptr插入到地图中。 地图的定义是这样的:

std::map<std::string,void(derived::*)()> m_func;

插入命令是这样的:

`m_func.insert(make_pair("yaodav",&derived::HelloWorld));`

这是整个代码:

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <any>
#include <typeinfo>
#include <typeindex>
using namespace std;


template<class Derived>
class base

public:
    void clean()
    
        cout << "I'm cleannig \n";
    
    void process()
    
        static_cast<Derived*>(this)->setup();
        static_cast<Derived*>(this)->run();
        static_cast<Derived*>(this)->cleanup();
    
;


class derived : public  base<derived> 

    friend class base<derived>;
    void setup() 
        m_func.insert(make_pair("yaodav",&derived::HelloWorld));
        cout << "derived setup \n"; 
    void run()  cout << "derived run \n"; 
    void cleanup()  cout << "derived cleanup \n"; 
    void HelloWorld() cout << "hwllo from derived \n"; 
    std::map<std::string,void(derived::*)()> m_func;

;


class derived1 : public base<derived1> 

    friend class base<derived1>;
    void setup() cout << "derived1 setup \n"; 
    void run()  cout << "derived1 run \n"; 
    void cleanup()  cout << "derived1 cleanup \n"; 
    void HelloWorld()
;

template <class T>
class Y
 public:
 std::vector<std::any> m_vec;   

;


template <typename T>
class D:public Y<T>

    public:
    friend class Y<T>;
    void print()
    
        for(auto& e: Y<T>::m_vec)
        
             if(e.type()==typeid(base<derived1>*))
            
                try 
                    auto* r = any_cast<base<derived1>*>(e);
                    r->process();
                
                catch(const std::bad_any_cast& e) 
                    std::cout << e.what() << '\n';
                
            
            else
            
                try 
                    auto *r = any_cast<base<derived> *>(e);
                    r->process();
                
                catch(const std::bad_any_cast& e) 
                    std::cout << e.what() << '\n';
                
            

        
     
;


int main()

        base<derived>* b =  new base<derived>;
        base<derived1>* c =  new base<derived1>;

        D<derived> y;
        y.m_vec.push_back(b);
        y.m_vec.push_back(c);
        y.print();

但是当调用插入函数(粗体部分)时,我遇到了分段错误,这就像我运行调试器时 m_func 不存在并且我不会打印我得到的 m_func:

这里没有名为 m_func 的成员或方法

为什么会发生这种情况以及如何解决它

修复

 base<derived>* b =  new derived;
 base<derived1>* c =  new derived1;

而不是

 base<derived>* b =  new base<derived>;
 base<derived1>* c =  new <derived1>;

【问题讨论】:

@lubgr tnx,修复它 您有一个将其派生类作为模板参数的基类?那么你的公共朋友类是基类吗?我希望这只是一个实验,因为这是一个非常糟糕且容易出错的设计......使用std::any 你会阻止任何静态代码分析(例如智能感知)来帮助你解决这个问题。 @JHBonarius 这个设计是为低延迟程序设计的,你不会防止 vTable 和 Cache 未命中。如果你不想在 youtube 上看到它的讲座 youtube.com/watch?v=vzDl0Q91MrM&t=173s thx... 看起来不是很快... 我会调查一下... 同时,您明白答案了吗? base&lt;derived&gt;* b = new base&lt;derived&gt;; 必须是 base&lt;derived&gt;* b = new derived;。但是你有内存泄漏。并且在base 中缺少一个虚拟析构函数。如果基础不正确,请不要尝试复杂的东西。 另外,关于克服继承的另一个很好的演示:youtube.com/watch?v=PSxo85L2lC0 【参考方案1】:

你的代码大致相当于这个:

base<derived>* b = new base<derived>;
b->process();

process 内部,有static_cast&lt;Derived*&gt;(this) - 但b 指向的base&lt;derived&gt; 的实例不是实际上是derived 的实例。您已独立实例化 base&lt;derived&gt;,而不是作为 derived 实例的一部分。您的程序从未创建过derived 的实例,也没有创建过derived1。所以你试图调用一个从未存在过的对象的成员函数,因此你的程序表现出未定义的行为。


更精简的代码版本如下所示:

class Base;
class Derived : public Base 
public:
  void DoSomething() ;
;

int main() 
  Base* b = new Base;
  static_cast<Derived*>(b)->DoSomethind();  // undefined behavior here

这样,问题应该更清楚了。

【讨论】:

我希望你的意思是Base* b = new Derived;...否则这是UB...哦,等等,这就是您要指出的... @JHBonarius 添加了一条评论以使其更加清晰。

以上是关于将成员函数 ptr 插入地图的主要内容,如果未能解决你的问题,请参考以下文章

获取函数 ptr 到实例类的成员函数?

如何将非静态成员函数作为unique_ptr删除器传递[重复]

将成员函数传递给函数指针

使用显式定义的默认构造函数将 unique_ptr 的类内成员初始化程序设置为 nullptr 错误

指向重载静态成员的函数指针 - 在 unique_ptr 中用作自定义删除器

如何在构造函数中为成员 unique_ptr 赋予默认值? [复制]