Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Const-correctness of std::reference_wrapper

A const std::reference_wrapper works similar to a reference, or a T* const (demo):

#include <functional>

struct S {
    void operator()() { i++; }
    int i = 0;
};

int main() {
    S s;
    const std::reference_wrapper<S> r = s;
    // now s.i == 0
    r();
    // now s.i == 1

    S* const p = &s;
    // now s.i == 1
    (*p)();
    // now s.i == 2
}

r is const, and std::reference_wrapper::operator() is a const method, thus we can call it, which in turn modifies the pointee. But, this operator() is a standard library function, thus [res.on.data.races]#3 quoted from the C++23 standard applies to it:

A C++ standard library function shall not directly or indirectly modify objects ([intro.multithread]) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function's non-const arguments, including this.

Does std::reference_wrapper violate this rule?

like image 528
Dr. Gut Avatar asked Oct 29 '25 10:10

Dr. Gut


1 Answers

Problem is that std::reference_wrapper<S> does not store a value, but reference. std::reference_wrapper<S> is not changed, but S s; is changed.

It is like holding a constant pointer to modifiable object.

So everything is ok. r remains unchanged. s is updated. So const version of function call operator is called and this member function call function call operator on s which is not const.

Documentation clearly states that operator() for is const

template< class... ArgTypes >
std::invoke_result_t<T&, ArgTypes...>
    operator() ( ArgTypes&&... args ) const noexcept(/* see below */);
like image 103
Marek R Avatar answered Nov 01 '25 01:11

Marek R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!