0%

tricky around c++ unique_ptr and callback

Background

  • Currently our team is working with a kind of Graph Processing Engine. At first glance, we implement it using EDP(event-driven-programming) based on DAG. But we found that DAG is not powerful enough for future extension like:
      1. Cycle
      1. Dynamic Graph
  • So we decide to Implement it using MDP(message-driven-programming). each time a msg is received, it will trigger a callback function to process the msg.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <memory>
#include <set>
#include <functional>

class Message;

class MessagePolaris {
public:
using Ptr = std::unique_ptr<MessagePolaris>;
void SetCallBack(std::function<bool (const std::set<std::string>&, Message*)> call_back) {
call_back_ = call_back;
}

private:
std::function<bool (const std::set<std::string>&, Message*)> call_back_;
};

class TaskPlan {
public:
using Ptr = std::unique_ptr<TaskPlan>;

private:
bool OnMessage(const std::set<std::string>& receivers, Message* msg) {
// deal msg
return true;
}

private:
MessagePolaris::Ptr msg_polaris_;
};


Problem

  • Consider following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main() {
auto task_plan = std::make_unique<TaskPlan>();

task_plan->msg_polaris_ = std::make_unique<MessagePolaris>();
task_plan->msg_polaris_->SetCallBack(
[&](const std::set<std::string>& receivers, Message* msg) {
return task_plan->OnMessage(receivers, msg);
});

auto dup_task_plan = std::move(task_plan);

// trigger callback

return 0;
}
  • The above could would coredump. The right way is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main() {
auto task_plan = std::make_unique<TaskPlan>();

task_plan->msg_polaris_ = std::make_unique<MessagePolaris>();

auto task_plan_raw_ptr = task_plan.get();
task_plan->msg_polaris_->SetCallBack(
[&](const std::set<std::string>& receivers, Message* msg) {
return task_plan_raw_ptr->OnMessage(receivers, msg);
});

auto dup_task_plan = std::move(task_plan);

// trigger callback

return 0;
}

Analysis