这是一个冗长的问题,但是我无法找出一种更简单的方式来解释正在发生的事情。
首先是这个包含std::function
回调的低级模板类(假设HeaderOne和HeaderTwo被定义为两个不同的结构):
template <class Type>
class TemplateClass
{
public:
template<class Type>
TemplateClass(Type t): type_{t} {}
std::function<void(char*, size_t)> on_callback;
void CheckHeader(char*, size_t);
private:
Type type_;
};
typedef TemplateClass<HeaderOne> HeaderOneClass;
typedef TemplateClass<HeaderTwo> HeaderTwoClass;
然后另一个类包含一个由int索引的HeaderTwoClass映射:
class Processor
{
public:
Processor(){}
void ProcessPacket(char*, size_t);
void AddHeaderClass(int i);
private:
std::map<int, HeaderTwoClass> hdrs_;
};
AddHeaderClass
的实现:void Processor::AddHeaderClass(int i)
{
HeaderTwoClass new_hdr;
auto [it, inserted] = hdrs_.insert({i, std::move(new_hdr)});
it->second.on_callback = [this](char* d, size_t i){ this->ProcessPacket(d, i); };
}
还有其他一些套接字类调用
HeaderTwoClass::CheckHeader
,如果检查通过,它将调用on_callback
。我得到的问题是,当调用on_callback
时,程序出现段错误。如果仅用类型
HeaderTwoClass
的成员替换地图,问题就会消失。我试图通过打印出
on_callback
的内存地址来调试它,但是发现它可以执行以下操作:首次构造
HeaderTwoClass
时,&on_callback = 123456HeaderTwoClass
移入地图后,&on_callback =78910
首次调用
on_callback
时,&on_packet = 123456。似乎on_callback指向std :: move之前的某个内存区域,即使我在之后设置了回调也是如此?
有任何想法吗?在这一点上,我很困惑。我还尝试编写一个最小的可编译示例,以简化和重现该错误,但未能成功。
请注意,此代码也是单线程的。
最佳答案
第一次构造HeaderTwoClass
时,&on_callback
= 123456
将HeaderTwoClass
移入地图后,&on_callback
= 78910
这一点都不奇怪-您正在检查类型中的std::function
成员的地址(基本上只是this
的偏移量)。当您将对象移动到地图中时,最终的结果是它是移动构造的-这意味着一个新的不同对象(尽管进行了移动,从语义上讲,还是可以从旧对象中窃取或swap
资源)。因此,这也许是您问题的根源。如果需要避免这种情况,请改用某种指针类型(例如shared_ptr
)-或使用map
直接在emplace
内部构造。