【问题标题】:Do objects captured by a lambda exist for as long as the lambda?lambda 捕获的对象是否存在与 lambda 一样长的时间?
【发布时间】:2023-01-10 12:10:20
【问题描述】:

我一直认为 lambda 只是函数指针,但我从未想过认真使用捕获语句......

如果我创建一个通过副本捕获的 lambda,然后将该 lambda 移动到一个完全不同的线程并且不尝试保存 lambda 中使用的原始对象,它会为我保留那些副本吗?

std::thread createThread() {
    std::string str("Success");
    auto func = [=](){ 
        printf("%s", str.c_str());
    };
    str = "Failure";
    return std::thread(func);
}

int main() {
    std::thread thread = createThread();
    thread.join();  
    // assuming the thread doesn't execute anything until here...
    // would it print "Success", "Failure", or deference a dangling pointer?
    return 0;
}

【问题讨论】:

    标签: c++ multithreading lambda


    【解决方案1】:

    保证打印Success。按副本捕获完全按照它说的去做。它就在那里制作对象的副本并将该副本存储为闭包对象的一部分。从捕获创建的闭包对象的成员与闭包对象本身一样长。

    lambda 不是函数指针。 Lambda 是可以具有内部状态的通用函数对象,这是函数指针所没有的。事实上,只有无捕获的 lambda 可以转换为函数指针,因此有时可能表现得像一个。

    lambda 表达式产生一个基本上看起来像这样的闭包类型:

    struct /*unnamed1*/ {
        /*unnamed1*/(const /*unnamed1*/&) = default;  
        /*unnamed1*/(/*unnamed1*/&&) = default;           
    
        /*unnamed1*/& operator=(const /*unnamed1*/&) = delete;       
    
        void operator() const {
            printf("%s", /*unnamed2*/.c_str());
        };
    
        std::string /*unnamed2*/;  
    };
    

    func是这个类型的对象,/*unnamed2*/被初始化为str的当前值。

    【讨论】:

      【解决方案2】:

      你有3种情况

      1. 您可以通过设计保证变量比线程的寿命更长,因为您在变量超出范围之前与线程的末尾同步。
      2. 您知道您的线程可能比您的线程的范围/生命周期更长,但您不再需要从任何其他线程访问变量。
      3. 您不能说哪个线程寿命最长,您有多个线程访问您的数据并且您想延长变量的寿命

        情况 1. 通过引用捕获

        情况 2. 按值捕获(或者你甚至使用移动)变量

        在案例 3 中,使数据共享,std::shared_ptr 并按值捕获它

        情况 3 会将数据的生命周期延长到最长存活线程的生命周期。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-09
        相关资源
        最近更新 更多