如何编写用于延迟初始化的C++ Lambda签名(模板实现)
用Lambda实现C++对象延迟初始化的正确写法
问题描述
需要实现对象的延迟初始化逻辑:当获取对象失败时,调用传入的Lambda创建对象并存储,后续调用直接返回已创建的对象。原代码因Lambda签名、函数参数写法等问题无法编译,以下是修正方案。
原错误代码
#include <iostream> #include <string> typedef std::string S; template <typename T> static inline T* getOrCreate( ( []() -> auto) creationSpren *) { bool assigned = false; if (!assigned) { // invoke creationSpren with passed arguments // assign } } int main() { auto& xx = []() { return new std::string("abc"); }; auto& zzz = getOrCreate<S>(xx); }
编译错误(中文翻译)
<source>: 在lambda函数中: <source>:7:45: 错误: 应为'{'在')'之前 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ^ <source>: 在全局作用域: <source>:7:46: 错误: 应为')'在'creationSpren'之前 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ~ ^~~~~~~~~~~~~~ | ) <source>:7:63: 错误: 应为';'在'{'之前 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ^~ | ; <source>: 在函数'int main()'中: <source>:18:16: 错误: 无法将非const左值引用'main()::<lambda()>&'绑定到右值'main()::<lambda()>' 18 | auto& xx = []() { | ^~~~~~ 19 | return new std::string("abc"); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | }; | ~ <source>: 在'std::__cxx11::basic_string<char>* getOrCreate<std::__cxx11::basic_string<char> >'的实例化中: <source>:22:17: 要求来自这里 <source>:7:33: 错误: 无法将'<lambda()>'转换为'std::__cxx11::basic_string<char>*'用于初始化 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ^~~~~~~~~~~~ | | | <lambda()> <source>:22:31: 错误: 'getOrCreate<std::__cxx11::basic_string<char> >'不能被用作函数 22 | auto& zzz = getOrCreate<S>(xx); | ~~~~~~~~~~~~~~^~~~ ASM生成编译器返回: 1 <source>: 在lambda函数中: <source>:7:45: 错误: 应为'{'在')'之前 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ^ <source>: 在全局作用域: <source>:7:46: 错误: 应为')'在'creationSpren'之前 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ~ ^~~~~~~~~~~~~~ | ) <source>:7:63: 错误: 应为';'在'{'之前 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ^~ | ; <source>: 在函数'int main()'中: <source>:18:16: 错误: 无法将非const左值引用'main()::<lambda()>&'绑定到右值'main()::<lambda()>' 18 | auto& xx = []() { | ^~~~~~ 19 | return new std::string("abc"); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 | }; | ~ <source>: 在'std::__cxx11::basic_string<char>* getOrCreate<std::__cxx11::basic_string<char> >'的实例化中: <source>:22:17: 要求来自这里 <source>:7:33: 错误: 无法将'<lambda()>'转换为'std::__cxx11::basic_string<char>*'用于初始化 7 | static inline T* getOrCreate( ( []() -> auto) creationSpren *) { | ^~~~~~~~~~~~ | | | <lambda()> <source>:22:31: 错误: 'getOrCreate<std::__cxx11::basic_string<char> >'不能被用作函数 22 | auto& zzz = getOrCreate<S>(xx); | ~~~~~~~~~~~~~~^~~~ 执行构建编译器返回: 1
错误原因分析
- 函数参数写法非法:C++不能直接用Lambda语法作为函数参数的类型声明,需通过模板参数或
std::function指定。 - Lambda引用绑定错误:非const左值引用无法绑定临时Lambda对象(Lambda表达式是右值),需改为值传递或
const auto&。 - 函数无返回值:
getOrCreate声明返回T*,但函数体内未编写任何return语句。 - 延迟初始化逻辑缺失:仅定义了
assigned变量,未实际存储创建的对象,也没有返回逻辑。
修正后的代码
#include <iostream> #include <string> typedef std::string S; // 模板版本:自动推导Lambda类型,无额外开销 template <typename T, typename Creator> static inline T* getOrCreate(Creator creator) { static T* instance = nullptr; // 静态变量存储对象,保证全局唯一且延迟初始化 if (!instance) { instance = creator(); // 调用Lambda创建对象 } return instance; } int main() { // 用auto直接存储Lambda,避免引用绑定问题 auto xx = []() { return new std::string("abc"); }; // 用指针接收返回值,避免引用绑定指针的错误 auto* zzz = getOrCreate<S>(xx); std::cout << *zzz << std::endl; // 输出abc // 再次调用返回同一个对象 auto* zzz2 = getOrCreate<S>(xx); std::cout << (zzz == zzz2) << std::endl; // 输出1,说明是同一指针 // 手动释放内存,实际项目建议用智能指针 delete zzz; return 0; }
关键修正点说明
- 函数参数类型:用模板参数
Creator自动推导Lambda类型,比std::function更高效;若需显式指定签名,可替换为std::function<T*()>。 - 静态存储对象:
static T* instance保证对象在第一次调用时初始化,后续调用直接返回已创建的实例。 - Lambda绑定:直接用
auto存储Lambda对象,解决右值无法绑定非const引用的问题。 - 返回值处理:函数返回对象指针,main中用指针类型接收,避免引用绑定指针的错误。
进阶优化:用智能指针避免内存泄漏
实际项目中推荐用std::unique_ptr或std::shared_ptr管理内存,无需手动释放:
#include <iostream> #include <string> #include <memory> typedef std::string S; template <typename T, typename Creator> static inline std::unique_ptr<T> getOrCreate(Creator creator) { static std::unique_ptr<T> instance; if (!instance) { instance = creator(); } return instance; // C++17起支持返回拷贝,内部自动转移所有权 } int main() { auto xx = []() { return std::make_unique<S>("abc"); }; auto zzz = getOrCreate<S>(xx); std::cout << *zzz << std::endl; auto zzz2 = getOrCreate<S>(xx); std::cout << (zzz.get() == zzz2.get()) << std::endl; // 智能指针自动管理内存,无需手动delete return 0; }
内容的提问来源于stack exchange,提问作者ycomp
相关产品推荐
相关产品推荐

