Dem*_*emi 7 c++ lambda smart-pointers
捕获lambda中智能指针的最佳方法是什么?我的一次尝试导致了一个免费使用后的bug.
示例代码:
#include <cstring>
#include <functional>
#include <memory>
#include <iostream>
std::function<const char *(const char *)> test(const char *input);
int main()
{
std::cout.sync_with_stdio(false);
std::function<const char *(const char *)> a = test("I love you");
const char *c;
while ((c = a(" "))){
std::cout << c << std::endl;
}
return 0;
}
std::function<const char *(const char *)> test(const char *input)
{
char* stored = strdup(input);
char *tmpstorage = nullptr;
std::shared_ptr<char> pointer = std::shared_ptr<char>(stored, free);
return [=](const char * delim) mutable -> const char *
{
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
};
}
Run Code Online (Sandbox Code Playgroud)
失败,如AddressSanitizer所示.
lambda(即使是具有通用捕获功能的lambda [=])实际上只捕获其定义中使用的变量.因为在你的例子中,pointer从未在lambda中使用过,所以它没有被捕获,因此当它超出范围时,它是最后一个引用stored并被free()调用的共享指针.
如果你想捕获pointer,你可以强制使用它:
return [=](const char * delim) mutable -> const char *
{
pointer;
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
};
Run Code Online (Sandbox Code Playgroud)
然而,这是相当hackish.您希望您的仿函数具有状态并且具有非常重要的状态管理.对我来说,这是一个强有力的指标,实际的命名类(而不是lambda)将是有序的.所以我会改变它:
std::function<const char *(const char *)> test(const char *input)
{
struct Tokenizer
{
std::shared_ptr<char> pointer;
char* stored;
char* tmpstorage;
explicit Tokenizer(char* stored) : pointer(stored, free), stored(stored), tmpstorage(nullptr) {}
const char* operator() (const char * delim)
{
const char *b = strtok_r(stored, delim, &tmpstorage);
stored = nullptr;
return b;
}
};
return Tokenizer(strdup(input));
}
Run Code Online (Sandbox Code Playgroud)