这是一个冗长的问题,但是我无法找出一种更简单的方式来解释正在发生的事情。

首先是这个包含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 = 123456
HeaderTwoClass移入地图后,&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内部构造。

10-08 11:53