Always declare std::mutex as mutable in C++11?

前端 未结 4 1283
甜味超标
甜味超标 2020-12-23 13:55

After watching Herb Sutter\'s talk You Don\'t Know const and mutable, I wonder whether I should always define a mutex as mutable? If yes, I guess the same holds for any sync

4条回答
  •  时光取名叫无心
    2020-12-23 14:39

    I just watched the talk, and I do not entirely agree with what Herb Sutter is saying.

    If I understand correctly, his argument is as follows:

    1. [res.on.data.races]/3 imposes a requirement on types that are used with the standard library -- non-const member functions must be thread-safe.

    2. Therefore const is equivalent to thread-safe.

    3. And if const is equivalent to thread-safe, the mutable must be equivalent to "trust me, even the non-const members of this variable are thread-safe".

    In my opinion, all three parts of this argument are flawed (and the second part is critically flawed).

    The problem with 1 is that [res.on.data.races] gives requirements for types in the standard library, not types to be used with the standard library. That said, I think it is reasonable (but not entirely clear-cut) to interpret [res.on.data.races] as also giving requirements for types to be used with the standard library, because it would be practically impossible for a library implementation to uphold the requirement to not modify objects through const references if const member functions were able to modify objects.

    The critical problem with 2 is that while it is true (if we accept 1) that const must imply thread-safe, it is not true that thread-safe implies const, and so the two are not equivalent. const still implies "logically immutable", it is just that the scope for "logically immutability" has expanded to require thread-safety.

    If we take const and thread-safe to be equivalent, we lose the nice feature of const which is that it allows us to easily reason about code by seeing where values can be modified:

    //`a` is `const` because `const` and thread-safe are equivalent.
    //Does this function modify a?
    void foo(std::atomic const& a);
    

    Furthermore, the relevant section of [res.on.data.races] talks about "modifies", which can be reasonably interpreted in the more general sense of "changes in an externally observable way", rather than just "changes in a thread-unsafe way".

    The problem with 3 is simply that it can only be true if 2 is true, and 2 is critically flawed.


    So to apply this to your question -- no, you should not make every internally synchronised object mutable.

    In C++11, as in C++03, `const` means "logically immutable" and `mutable` means "can change, but the change will not be externally observable". The only difference is that in C++11, "logically immutable" has been expanded to include "thread-safe".

    You should reserve mutable for member variables that do not affect the externally visible state of the object. On the other hand (and this is the key point that Herb Sutter makes in his talk), if you have a member that is mutable for some reason, that member must be internally synchronised, otherwise you risk making const not imply thread-safe, and this would cause undefined behaviour with the standard library.

提交回复
热议问题