ben23f
ben23f

Reputation: 47

Memory corruption when calling std::function member

This is a bit of a long winded question but I cannot figure out a simpler way of explaining what is going on.

First is this low level template class which contains the std::function callback (assume HeaderOne and HeaderTwo are defined as two different structs):

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;

Then another class contains a map of HeaderTwoClass indexed by an int:

class Processor
{
public:
    Processor(){}
    void ProcessPacket(char*, size_t);
    void AddHeaderClass(int i);

private:
    std::map<int, HeaderTwoClass> hdrs_;
};

The implementation of 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); };
}

There is some other socket class that calls HeaderTwoClass::CheckHeader and if the check passes it calls on_callback. The problem I get is that when on_callback is called, the program segfaults.

If I replace the map with just a member of type HeaderTwoClass the problem goes away.

I have tried to debug it by printing out the memory address of on_callback but have found it does the following:

It seems that the on_callback is pointing to some area of memory before the std::move even though I set the callback after?

Any ideas? I'm stumped at this point. I also tried to write a minimal compile-able example to simplify and reproduce the error but was unable.

Note this code is all single threaded as well.

Upvotes: 0

Views: 251

Answers (1)

darune
darune

Reputation: 11000

  • when HeaderTwoClass is first constructed, &on_callback = 123456
  • after the HeaderTwoClass is moved into the map, &on_callback = 78910

This isn't strange at all - you are checking the address of the std::function member in the type (which is basically just an offset to this). When you move the object into the map then end result is that it is move constructed - that means a new distinct object (albeit with a move it's semantically fine to steal or swap resources off the old object). So perhaps this is the root to your issue. If you need to avoid that, use some pointer type instead (e.g. shared_ptr) - or construct directly inside the map using emplace.

Upvotes: 1

Related Questions