0

Why does this code

#include <functional>
#include <iostream>
#include <memory>

struct Result {
  string value;
};

class BaseHandler {
 public:
  BaseHandler() {}
  void Handle() { std::cout << "Base Handler " << endl; }

  ~BaseHandler() {}
};

class Handler : public BaseHandler {
 public:
  Handler(const Result& result) : result_(result) {}
  void Handle() { std::cout << "Result: " << result_.value << endl; }

  ~Handler() {}

 private:
  Result result_;
};

class Dispatcher {
 public:
  void Dispatch() {
    std::unique_ptr<BaseHandler> handler = create_handler_();
    handler->Handle();
  }
  std::function<std::unique_ptr<BaseHandler>()> create_handler_;
};

void SetHandler(Dispatcher* dispatcher, Result some_result) {
  dispatcher->create_handler_ =
      [some_result]() -> std::unique_ptr<BaseHandler> {
    std::unique_ptr<BaseHandler> handler(new Handler(some_result));
    return handler;
  };
}

int main(int argc, char** argv) {
  Result some_result;
  some_result.value = "some_value";
  Dispatcher dispatcher;
  SetHandler(&dispatcher, some_result);

  dispatcher.Dispatch();
  return 0;
}

Produce the error

F0731 11:28:05.092886   61642 debugallocation.cc:762] RAW: delete size mismatch: passed size 1 != true size 32
    @           0x49f053  (anonymous namespace)::RawLogVA()
    @           0x49ec05  base_raw_logging::RawLog()
    @           0x56d51b  tc_delete_sized
    @           0x40e65b  std::default_delete<>::operator()()
    @           0x40e513  std::unique_ptr<>::~unique_ptr()
    @           0x40da86  Dispatcher::Dispatch()
    @           0x40d527  main
    @     0x7f393a983ce8  __libc_start_main
    @           0x40cef9  _start
*** SIGABRT received by PID 61642 (TID 61642) from PID 61642; ***
Aborted (core dumped)
Jeremy Lewi
  • 6,386
  • 6
  • 22
  • 37
  • 1
    Haven't you ever wondered what the `virtual` keyword was for? Now is a good time to [find a good beginners book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) and start reading about `virtual` member functions and inheritance. – Some programmer dude Jul 31 '16 at 18:38
  • Not the downvoter, but I think I'll simply leave you alone with that. Arguable if repeating trivia is actually useful. Maybe you should try at [tag:documentation]. – πάντα ῥεῖ Jul 31 '16 at 18:39
  • @JoachimPileborg You noticed our new ghetto for poor canonical attemts? – πάντα ῥεῖ Jul 31 '16 at 18:40

1 Answers1

3

The problem is the destructor of BaseHandler and Handler aren't declared virtual.

If Handle had been marked as virtual in BaseHandler and override in Handler then the compiler would have generated an error about the destructor not being declared virtual.

The code below works as expected.

#include <functional>
#include <iostream>
#include <memory>

struct Result {
  string value;
};

class BaseHandler {
 public:
  BaseHandler() {}
  virtual void Handle() { std::cout << "Base Handler " << endl; }

  virtual ~BaseHandler() {}
};

class Handler : public BaseHandler {
 public:
  Handler(const Result& result) : result_(result) {}
  void Handle() override { std::cout << "Result: " << result_.value << endl; }

  virtual ~Handler() {}

 private:
  Result result_;
};

class Dispatcher {
 public:
  void Dispatch() {
    std::unique_ptr<BaseHandler> handler = create_handler_();
    handler->Handle();
  }
  std::function<std::unique_ptr<BaseHandler>()> create_handler_;
};

void SetHandler(Dispatcher* dispatcher, Result some_result) {
  dispatcher->create_handler_ =
      [some_result]() -> std::unique_ptr<BaseHandler> {
    std::unique_ptr<BaseHandler> handler(new Handler(some_result));
    return handler;
  };
}

int main(int argc, char** argv) {
  Result some_result;
  some_result.value = "some_value";
  Dispatcher dispatcher;
  SetHandler(&dispatcher, some_result);

  dispatcher.Dispatch();
  return 0;
}
Jeremy Lewi
  • 6,386
  • 6
  • 22
  • 37