为何以std::function形式调用operator()无法正常工作?
问题分析:std::function包装issues_t后无法修改原对象的原因
我写了一个用来收集字符串序列的小型类:
class issues_t final { private: std::vector<std::string> m_issues; public: constexpr void operator()(std::string&& txt) { m_issues.push_back( std::move(txt) ); } };
我计划这样使用它:
issues_t issues; do_something(issues);
下面这种写法能正常工作:
void do_something(issues_t& notify_issue) { notify_issue("something"); }
但我更想用下面这种方式:
using fnotify_t = std::function<void(std::string&&)>; void do_something(fnotify_t const& notify_issue) { notify_issue("something"); }
这种写法能编译通过,但实际运行时,虽然push_back()执行了,底层的vector却没有被填充。最小可复现示例如下:
#include <string> #include <vector> #include <functional> #include <print> class issues_t final { private: std::vector<std::string> m_issues; public: constexpr void operator()(std::string&& txt) { m_issues.push_back( std::move(txt) ); } [[nodiscard]] constexpr auto begin() const noexcept { return m_issues.cbegin(); } [[nodiscard]] constexpr auto end() const noexcept { return m_issues.cend(); } }; using fnotify_t = std::function<void(std::string&&)>; void do_first(fnotify_t const& notify_issue) { notify_issue("do_first"); } void do_second(issues_t& notify_issue) { notify_issue("do_second"); } int main() { issues_t issues; issues("main"); do_first(issues); do_second(issues); for( const auto& issue : issues ) { std::print(" {}\n", issue); } }
问题原因
当你把issues_t对象直接传给std::function时,std::function会拷贝一份原对象,而不是存储原对象的引用。后续调用notify_issue("do_first")时,实际操作的是std::function内部的那份拷贝,原issues对象完全没被修改,所以你看不到"do_first"被添加进去。
解决方案
要让std::function操作原对象,你需要存储原对象的引用,最简洁的方式是用std::ref包装原对象:
修改main中的调用:
do_first(std::ref(issues));
这样std::function会存储原对象的引用,后续调用时就会直接操作原issues对象。
验证结果
修改后的main函数运行后,输出会包含:
main do_first do_second
完全符合预期。
内容的提问来源于stack exchange,提问作者MatG
相关产品推荐
相关产品推荐

