1

When I can, and when I can not call variable mutable?

It is very clear with int/float/bool value. But what about, let's say, array. Can I call native array mutable, if I gonna add elements to it? Same with std::vector.

One more example. I have object A, which keeps reference (B &b) to another object B. Object B have native array which I will reallocate/ std::vector (which I think is similar in this particular case ). Pseudo-code:

struct B{
   std::vector<int> arr;
   // int *arr;              //Or this
   void changeArr(){
     arr.push_back(90);
   }
}

struct A{
   A(B &b) : b(b){};
   mutable B &b;     // is it ok to have it "mutable"?
   //mutable B b;    // or even this?
   void fire() const{
      b.arr.push_back(125);
      // Or 
      b.changeArr();
   }
}

Can I call B &b mutable?


UPDATE

According to http://en.cppreference.com/w/cpp/language/cv:

mutable - defines that a member of a class does not affect the externally visible state of the class.

What is this externally visible state of the class ? Do I change it when I increase array size, reallocate something? If no, when it changes at all?

tower120
  • 5,007
  • 6
  • 40
  • 88
  • `mutable` is like `const` or `volatile` – yizzlez Jun 17 '14 at 15:38
  • http://stackoverflow.com/questions/2444695/volatile-vs-mutable-in-c – Ashalynd Jun 17 '14 at 15:42
  • Only any member variable that is not `const` or `static` may be `mutable`. – Drew Dormann Jun 17 '14 at 15:43
  • 1
    Ok. But unlike `const`, http://en.cppreference.com/w/cpp/language/cv "mutable - defines that a member of a class does not affect the externally visible state of the class. " It should "not affect the externally visible state of the class". What is this "externally visible state of the class"? – tower120 Jun 17 '14 at 15:44
  • 1
    An example of the `mutable` keyword would be a mutable mutex in a class, that can be locked in a `const` function. The mutex cannot be `const` since it needs to be modified, but it needs to be modifyable in a const function, so it requires the `mutable` qualifier. – tillaert Jun 17 '14 at 15:50

1 Answers1

5

Let's give two classic examples on where mutable is helpful:

1. Remembering calculations (memoization)

class prime_caclulator {
    private:
        mutable std::vector<int> m_primes;

    public:
        get(int n) const {
            // 1. If the nth prime is in m_primes, return it.
            // 2. Otherwise, calculate the nth prime.
            // 3. Store the nth prime in m_primes.
            // 4. Return that prime.
        }
};

Here, we have a const function get() that doesn't need to change the internal state of this object to calculate the nth prime. But, it could be helpful to keep track of previously calculated primes, to improve the performance of this object.

This internal state, which here we call m_primes, might change when get() is called so we need to mark it as mutable. Note that the varying contents of that object only changes how long this call takes, not what it ends up returning.

2. Thread Safety

template <typename T>
class thread_safe_queue {
    private:
        mutable std::mutex m_mutex;
        std::queue<T> m_queue;

    public:
        size_t size() const {
            std::lock_guard<std::mutex> lock(m_mutex);
            return m_queue.size();
        }

        void push(T value) {
            std::lock_guard<std::mutex> lock(m_mutex);
            m_queue.push(value);
        }

        T pop() {
            std::lock_guard<std::mutex> lock(m_mutex);
            T top = m_queue.front();
            m_queue.pop();
            return top;
        }
};

In this case, if we didn't have a mutable mutex, then we would not be able to have size() be const, because we modify m_mutex in the process of that function.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • 1
    A third classic, justified use case for `mutable` is reference counting: If you have a class that keeps its own reference count, you want that reference count to be `mutable`. Adding a reference to an object does not change its logical state, and it should be possible to retain an object via a `const` pointer. – cmaster - reinstate monica Jun 17 '14 at 16:21
  • So, if I right understand point 1. It is ok (by design) to have mutable variable, which have both setter (non const) and getter (const). Just to clarify. http://coliru.stacked-crooked.com/a/0cc6b5f7a3b63dd6 – tower120 Jun 17 '14 at 17:43
  • @tower120: I'm honestly not sure if that example is well formed. For other readers, note that the object is returned by non-const reference. – Bill Lynch Jun 17 '14 at 18:30
  • As my answer was bashed and deleted ... example one is not valid. According to the gods of c++ http://channel9.msdn.com/posts/C-and-Beyond-2012-Herb-Sutter-You-dont-know-blank-and-blank mutable means bitwise const or internaly synchronized. That rule will be broken by our first example because you do not say anything about synchronization. The second example uses a mutex which is sychronized by default. ... and i do not think that the link will be out of date in the not so near future. – knivil Jun 17 '14 at 18:36
  • @sharth and if I add const reference to return value from get? http://coliru.stacked-crooked.com/a/0dd9171437de667b – tower120 Jun 17 '14 at 18:41
  • @knivil what is "internal synchronization"? – tower120 Jun 17 '14 at 18:43
  • synchronization/atomic access/transaction semantics/ ... that is not added explizitly by you as a user of that function/class/module. – knivil Jun 17 '14 at 18:46
  • `thread_safe_queue` is synchronized internally because you do not have to add synchronozation explizitly as a user of that class. you can use this class in a multithreaded context without thinking about synchronization. internal means implementation detail. – knivil Jun 17 '14 at 18:53
  • @tower120: If you return by const reference or value, then the vector doesn't need to be mutable. I'm just not sure about the contract when the return value is a reference. – Bill Lynch Jun 17 '14 at 19:31