我的lambda在复制构建期间没有正确转换捕获的"this"

My lambda does not correctly convert the captured 'this' during copy construction

本文关键字:转换 this 复制 lambda 构建 我的      更新时间:2023-10-16

我已经将问题缩小到了这个

#include <iostream>
#include <functional>
struct Foo {
    std::function<Foo*()> lambda;
    Foo()
        :lambda([this](){return this;})
    {}
};
int main(){
    Foo a;
    Foo b = a; 
    std::cout << &a << " " << a.lambda() << std::endl;
    std::cout << &b << " " << b.lambda() << std::endl;
}

输出为

0x7ffd9128b8a0 0x7ffd9128b8a0
0x7ffd9128b880 0x7ffd9128b8a0

我最初期望this总是指向拥有lambda的实例。但是,我忘记了复制构造。在这种情况下,Lambda捕获了this,然后固定,无论复制Lambda多少次,都指向this的原始值。

是否有一种方法来修复此操作,以便lambda始终对其拥有对象this的参考,即使在拥有对象的复制构造下也是如此。

听起来您需要提供自己的特殊会员功能,不是吗?例如,对于复制构造函数:

Foo(const Foo& other)
   :lambda([this](){return this;})
{}

,而@lubgr回答了我问的问题,我认为值得注意的是我确切的问题的其他解决方案。这个问题源于建立班级来封装成员的懒惰初始化。我最初的尝试是

template <typename T>
class Lazy {
    mutable boost::once_flag _once;
    mutable boost::optional<T> _data;
    std::function<T()> _factory;
    void Init() const { boost::call_once([&] { _data = _factory(); }, _once); }
public:
    explicit Lazy(std::function<T()> factory):_once(BOOST_ONCE_INIT),_factory(factory){}
    T& Value() {
        Init();
        return *_data;
    }
}; 

可以像

一样使用
class Foo { 
    int _a;
    Lazy<int> _val;
    Foo(a):_a(a):_val([this](){return this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value();

,但我在问题中提出的问题与this是一个循环参考,无法保留用于复制构造。该解决方案不是创建自定义复制构造函数,也可能是移动构造函数,而是要修复懒惰实现类,以便我们可以将ARG传递给工厂。

懒惰的新实施是

template <typename T, typename TThis>
class LazyMember {
    mutable boost::once_flag _once;
    mutable boost::optional<T> _data;
    typedef std::function<T(TThis const*)> FactoryFn;
    FactoryFn _factory;
    void Init(TThis const * arg0) const { boost::call_once([&] { _data = _factory(arg0); }, _once); }
public:
    explicit LazyMember(FactoryFn factory):_once(BOOST_ONCE_INIT),_factory(factory){}
    T& Value(TThis const * arg0) { Init(arg0); return *_data; }
    T const & Value(TThis const * arg0) const { Init(arg0); return *_data; }
}; 

用作

class Foo { 
    int _a;
    Lazy<int> _val;
    Foo(a):_a(a):_val([](Foo const * _this){return _this->_a+1;}){}
}
Foo f(10);
int val = f._val.Value(&f);

这没有循环参考问题,因此不需要自定义复制/移动构造函数。