我发现C++中的lambda函数可以绕过const限制,是bug吗?

问题描述 投票:0回答:1

我正在测试惰性求值的实现。为此,我将一个 lambda 函数作为参数传递给成员构造函数,该函数仅在第一次评估发生时执行。但是,我注意到 lambda 函数可以通过捕获的变量访问类成员变量,并且我可以在 lambda 函数内部修改它们。

我的 const 限制测试函数如下:

void print_root(const Foo& f) {
    for(auto i:iota(0,10)) std::cout << f.root() << std::endl;
}

实现如下

template<typename T>
class Lazy {
private:
    std::function<T()> get_value;
    mutable std::mutex mutex;
    mutable bool evaluated = false;
    mutable T value;
public:
    Lazy(std::function<T()> f) : get_value(f) {}
    const T& operator()() const {
        std::lock_guard<std::mutex> lock(mutex);
        if(!evaluated) {
            value = get_value();
            evaluated = true;
        }
        return value;
    }
};

struct Foo {
private:
    double x;
public:
    Lazy<double> root;
    Foo(double _x) : x(_x), root(
        [this]()->double { 
            double a = x/2;
            std::cout << "Calculating root of " << x << std::endl;
            for(auto i:iota(0, 1000000000)) a = (a + x/a) / 2;
            x = 3; //try to modify this-> x
            return a;
        }
    ) {}
};

然后 g++ 编译器不报告任何错误。

c++ gcc g++
1个回答
1
投票

捕获

this
的行为本质上就好像您已经捕获了具有相同类型的
this
的指针值,并且 lambda 主体中的每个成员访问都被重写为通过该捕获的指针进行访问。

root
的默认成员初始化器中,
this
的类型是
Foo*
,而不是
const Foo*
。所以捕获的
this
也将是非
const
。那么 lambda 的
operator()
是否符合
const
并不重要。如果你有一个
Foo* const
类型的指针,那么取消引用它仍然会给你一个
Foo
左值,而不是
const Foo
左值。

这与将指针存储为类成员完全相同:

struct Foo {
    int a = 0;

    Foo* x = this;

    void f() const {
        this->a++; // error, `this` is prvalue of type `const Foo*`
                   // so `*this` is lvalue of type `const Foo`
        x->a++;    // ok, `x` is lvalue of type `Foo* const`,
                   // after lvalue-to-rvalue conversion of type `Foo*`
                   // so `*x` is lvalue of type `Foo`
    }
};

(还请考虑我和其他人在有关设计和使用

Lazy
的一般问题的问题下发表的评论。)

© www.soinside.com 2019 - 2024. All rights reserved.