c ++ lambda在错误的地址/错误的上下文中执行

c++ lambda executed at wrong address / in wrong context

以下代码也可在 godbolt.org/z/SjkAWZ 获得。
我有一个带有 std::function 作为成员变量的结构,它由构造函数中的 lambda 表达式分配。 可以从构造函数成功调用 lambda,但不能从成员函数调用。

#include <vector>
#include <functional>

struct S
{
    S()
    {

        std::cout << "construct: " << reinterpret_cast<long>(this) << "   " << std::flush;
        std::cout << m_ << '\n';

        lambda_ = [&]() {
            std::cout << "lambda:    " << reinterpret_cast<long>(this) << "   " << std::flush;
            std::cout << m_ << '\n';
        };

        lambda_();
    }


    void foo()
    {
        std::cout << "foo:       " << reinterpret_cast<long>(this) << "   " << std::flush;
        std::cout << m_ << '\n';

        lambda_();
    }

private:
    int m_ = 3;  // some member variable
    std::function<void(void)> lambda_;
};



int main()
{
    std::vector<S> v;
    v.emplace_back();
    v.emplace_back();

    std::cout << "\n--- loop ---\n";

    for(auto& b : v)
    { b.foo(); }
}

可能的程序输出:

construct: 94159000759920   3
lambda:    94159000759920   3
construct: 94159000761048   3
lambda:    94159000761048   3

--- loop ---
foo:       94159000761008   3
lambda:    94159000759920   0  // <-- bad *this* address, bad value for m_
foo:       94159000761048   3
lambda:    94159000761048   3  // <-- bad *this* address, correct value for m_ (coincidence?)

如您所见,如果从成员函数 foo 调用 lambda 函数的上下文 this 是错误的。

有趣的是,如果我只在向量中放置一个元素,情况就不是这样了:

construct: 13753968   3
lambda:    13753968   3

--- loop ---
foo:       13753968   3
lambda:    13753968   3  // <-- correct *this* address and correct value for m_

我在 Debian 上使用 g++ 8.3.0 版。

我是否通过在适当的位置构造向量中的元素而导致未定义的行为?

您错过了结构的复制/移动构造函数!

如果您将一些变量分配给 std::vector,它有时会保留新内存并将所有内容复制到新内存。在您的情况下,lambda 不知道更改并保留对 S 的旧实例的引用。所以你的代码完全被破坏了。

您可以通过在分配内容之前预留足够的 space 来解决此问题:

int main()
{
    std::vector<S> v;
    v.reserve(5);
    ...
}

但这只是解决方法!您应该准备一个 move/copy 构造函数,以便能够获得实例的正确副本。