将成员函数 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<derived>* b = new base<derived>;
必须是 base<derived>* b = new derived;
。但是你有内存泄漏。并且在base
中缺少一个虚拟析构函数。如果基础不正确,请不要尝试复杂的东西。
另外,关于克服继承的另一个很好的演示:youtube.com/watch?v=PSxo85L2lC0
【参考方案1】:
你的代码大致相当于这个:
base<derived>* b = new base<derived>;
b->process();
在process
内部,有static_cast<Derived*>(this)
- 但b
指向的base<derived>
的实例不是实际上是derived
的实例。您已独立实例化 base<derived>
,而不是作为 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 插入地图的主要内容,如果未能解决你的问题,请参考以下文章
如何将非静态成员函数作为unique_ptr删除器传递[重复]
使用显式定义的默认构造函数将 unique_ptr 的类内成员初始化程序设置为 nullptr 错误