Лямбда захватывает эту и длительную функцию
У меня есть функция, которая требует много времени для запуска, но, к счастью, она работает асинхронно. Я хочу взять результат этого вызова функции и установить его в частную переменную экземпляра класса. Кажется легким:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
void Do() {
auto lambda = [this](int val) {
// Some processing...
var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
A* a = new A;
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
Проблема заключается в добавлении следующей строки main
Прямо перед комментарием:
delete a;
Теперь когда LongRunningAsync
вызывает обратный вызов, он попытается изменить переменную-член удаленного экземпляра (который является UB).
Есть ли способ спасти этот подход? Недавно я узнал о следующем решении:
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
std::weak_ptr<A> weak = shared_from_this();
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) return;
// Some processing...
shared->var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
auto a = std::make_shared<A>();
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
Но это требует изменения всех A
переменные для shared_ptr. Есть ли менее навязчивый способ сделать эту работу?
2 ответа
Одним из возможных решений является просто инкапсулировать нужное вам состояние в shared_ptr
переменная-член, а затем захватывает это значение по замыканию, которое выполняется асинхронно.
Что-то вроде следующего
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
auto lambda = [member_shared_state](int val) {
member_shared_state->var_ = val;
};
LongRunningAsync(lambda);
}
....
};
Вот решение, основанное на подходе Curious, но это не заставляет меня менять все указатели на A
возражает против shared_ptr
:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
A() : var_(std::make_shared<int>()) {}
void Do() {
std::weak_ptr<int> weak = var_;
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) {
return;
}
// Some processing...
*shared = val;
};
LongRunningAsync(lambda);
}
private:
std::shared_ptr<int> var_;
};
int main() {
A* a = new A;
a->Do();
delete a;
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}