简体   繁体   中英

C++ mutable specifier

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM