闭包的捕获变量存储在哪里?

5

我正在开发一款内存密集型的应用程序,需要能够正确处理内存不足的情况。

我有类似以下的代码

class memory_manager {
    // returns true if slot created (and function is being run)
    // false otherwise
    static bool create_slot(int id, std::function<void (slot&)>); ........
}

这个类处理、记录所有的内存不足问题,保持对所有插槽的所有权,并驱动并发。

但是,在以下代码中我没有处理好 std::bad_alloc

slot_data_to_copy dat;

memory_manager::create_slot(100, [&dat](slot& sx) { sx.assign_data(dat); });

我假设在捕获变量时执行了 throw 操作。(实际上,我捕获了更多变量,这只是一个示例)

闭包是在哪里创建的? 我能控制它吗?或者,如果我以一种接受参数的方式更新管理器,例如

slot_data_to_copy dat;

memory_manager::create_slot<slot_data_to_copy>
       (100, dat, [](slot& sx, slot_data_to_copy& dat) 
           { sx.assign_data(dat); }
       );

能否保证它完全不会抛出任何异常?

我在Windows上使用Visual C++和Linux上的GCC编译两者,但是我只观察到这种行为发生在Windows上(在Linux上,我可能会在可以处理的某个地方用尽内存)。

编辑:

http://en.cppreference.com/w/cpp/utility/functional/function/function - std::function包含nothrow运算符.. 我可能错过了什么,但是在这种(lambda)情况下使用哪一个?


我假设在捕获变量时会抛出异常。Lambda表达式被复制到堆上吗?它何时被释放? - nothrow
1
[expr.prim.lambda]/2 вҖңlambdaиЎЁиҫҫејҸзҡ„жұӮеҖјз»“жһңдёәprvalueдёҙж—¶еҜ№иұЎгҖӮиҜҘдёҙж—¶еҜ№иұЎз§°дёәй—ӯеҢ…еҜ№иұЎгҖӮвҖқ еңЁжӯӨеӨ„дҪҝз”Ёзҡ„std::functionзҡ„жһ„йҖ еҮҪж•°жҳҜtemplate< class F > function( F f );пјҢе®ғдёҚжҳҜnoexceptгҖӮ - dyp
2个回答

4

闭包是在哪里创建的?

lambda表达式会创建一个未命名类型的对象,它实际上是一个普通的函数对象类。被捕获的变量是该未命名类型的成员。

您的代码 memory_manager::create_slot(100, [&dat](slot& sx) { sx.assign_data(dat); }); 本质上与以下代码相同:

slot_data_to_copy dat;

struct unnamed_lambda_type {
  slot_data_to_copy &dat;

  unnamed_lambda_type(slot_data_to_copy &dat_) : dat(dat_) {}

  void operator() (slot &sx) const {
    sx.assign_data(dat);
  }
};

memory_manager::create_slot(100, unnamed_lambda_type(dat) );

闭包函数在哪里创建?

闭包对象就像其他临时对象一样,通常分配在堆栈上。


1
闭包就是lambda;捕获的变量是匿名结构体的数据成员(这就是lambda的含义)。创建lambda不会抛出bad_alloc异常;你的错误可能在其他地方(可能是创建std::function,它可能会将lambda复制到堆上)。
附注:在lambda中你正在通过引用捕获;确保slot_data_to_copy dat在调用lambda时不被销毁。你应该按值复制它或立即调用lambda。

好的,我假设 throw 是在捕获变量时发生的(如果是在 std::function<> 创建时抛出,我也不介意)。我希望 std::function 能够在堆栈上创建,这是否可能? - nothrow
std::function 作为参数传递,因此已经在堆栈上。std::function 内部有一个指向堆上 lambda 的指针(类似于 std::vector 可以在堆栈上但其数据在堆上)。 - Simple
附注:函数create_slot不会将lambda保存在任何地方,因此数据无法被销毁。 - nothrow
std::function的构造函数接受一个分配器,因此您可以通过这种方式进行控制。 - Simple

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接