代码之家  ›  专栏  ›  技术社区  ›  Chen Li

使用STD::函数作为成员函数,它捕获这个“”,并在析构函数之后从复制的lambda访问它

  •  3
  • Chen Li  · 技术社区  · 6 年前

    Flex Ferrum 发布代码示例 here (我想是的 最小、完整和可验证 够了):

    #include <iostream>
    #include <functional>
    using namespace std;
    
    class Bang
    {
    public:
        Bang(int i = 0) : m_val(i)
        {
            m_foo = [this] {std::cout << m_val << std::endl;};
        }
    
        ~Bang()
        {
            m_val = -1;
        }
    
        void Foo()
        {
            m_foo();
        }
    private:
        int m_val;
        std::function<void ()> m_foo;
    };
    
    Bang GetBang()
    {
        return Bang(100500);
    }
    
    int main() {
        Bang b(100500);
        b.Foo();
        b = GetBang();
        b.Foo();
        return 0;
    }
    

    我们的弹性也提供 live demo


    经过粗略的观察,我认为它会输出 100500 但实际产出是:

    -1
    
    • 为什么?它的背后是什么?
    • 如何修复?(输出 十万零五百 不是 -1 )

    我写了一些我自己的理由 ask box 但发现作为答案张贴更合适(会使问题太长)。如果我的答案是错误的,请改正,欢迎有更多的答案。

    2 回复  |  直到 6 年前
        1
  •  3
  •   Chen Li    6 年前

    Bang(100500) GetBang prvalue temporary object lifetime

    1. [this] will be stored as reference of *this

        class Lambda
        {
        public:
            void operator()() const
            {
                //output
            }
    
        private:
            Bang& bang;
    
        public:
            Lambda(Bang& bang) : bang{bang}
            {
            }
    
        } lambda{*this};
        ...
        m_foo = lambda;
    

    1. RVO b

    2. operator() constructor destructor


    #include <iostream>
    #include <functional>
    
    using namespace std;
    
    class Bang
    {
    public:
        Bang(int i = 0) : m_val(i)
        {
    
            std::cout << "Bang(int i = 0) m_val address is " << &m_val << '\n';
            class Lambda
            {
            public:
                void operator()() const
                {
    
                    std::cout << "operator() m_val address is " << &bang.m_val << '\n';
                    std::cout << bang.m_val << std::endl;
                }
    
            private:
                Bang &bang;
    
            public:
                Lambda(Bang &bang) : bang{bang}
                {
                }
    
            } lambda{*this};
            m_foo = lambda;
    
        }
    
        ~Bang()
        {
            std::cout << "~Bang()\n";
            m_val = -1;
        }
    
        void Foo()
        {
            m_foo();
        }
    
    private:
        int m_val;
        std::function<void()> m_foo;
    };
    
    Bang GetBang()
    {
        return Bang(100500);
    }
    
    int main()
    {
        Bang b;
        b = GetBang();
        b.Foo();
        return 0;
    }
    

    live demo

    Bang(int i = 0) m_val address is 0x7ffd202c48b0
    Bang(int i = 0) m_val address is 0x7ffd202c48e0
    ~Bang()
    operator() m_val address is 0x7ffd202c48e0
    -1
    ~Bang()
    

    • dtor
    • m_value

    m_foo()

    1. @Killzone Kid [bang = *this]
    2. [*this] live demo
        2
  •  0
  •   Killzone Kid    6 年前

    *this Bang this

    #include <iostream>
    #include <functional>
    
    class Bang
    {
    public:
        Bang(int i = 0) : m_val(i)
        {
            m_foo = [bang = *this] { std::cout << bang.m_val << std::endl; };
        }
    
        ~Bang()
        {
            m_val = -1;
        }
    
        void Foo()
        {
            m_foo();
        }
    private:
        int m_val;
        std::function<void()> m_foo;
    };
    
    Bang GetBang()
    {
        return Bang(100500);
    }
    
    int main()
    {
        Bang b;
        b = GetBang();
        b.Foo();
        return 0;
    }
    

    https://ideone.com/LUDrBb