不久前,我遇到了一些代码,它们用mutable关键字标记了一个类的成员变量。据我所知,它只是允许你在const方法中修改变量:

class Foo  
{  
private:  
    mutable bool done_;  
public:  
    void doSomething() const { ...; done_ = true; }  
};

这是唯一的使用这个关键字还是有更多的它比满足眼睛?从那以后,我在一个类中使用了这种技术,将boost::mutex标记为mutable,允许const函数出于线程安全的原因锁定它,但是,说实话,这感觉有点hack。


当前回答

关键字'mutable'实际上是一个保留关键字。它通常用来改变常数变量的值。如果你想要一个常量的多个值,使用关键字mutable。

//Prototype 
class tag_name{
                :
                :
                mutable var_name;
                :
                :
               };   

其他回答

在为类测试目的创建存根时,mutable关键字非常有用。你可以存根一个const函数,仍然能够增加(可变的)计数器或任何你已经添加到存根的测试功能。这使存根类的接口保持不变。

经典的例子(在其他回答中提到),也是我迄今为止看到的使用mutable关键字的唯一情况,是用于缓存复杂的Get方法的结果,其中缓存是作为类的数据成员实现的,而不是作为方法中的静态变量(出于几个函数之间共享或简单清洁的原因)。

一般来说,使用mutable关键字的替代方法通常是方法中的静态变量或const_cast技巧。

另一个详细的解释在这里。

Mutable将const的含义从按位的const更改为类的逻辑const。

这意味着具有可变成员的类将不再是按位的const,并且将不再出现在可执行文件的只读部分中。

此外,它通过允许const成员函数在不使用const_cast的情况下更改可变成员来修改类型检查。

class Logical {
    mutable int var;

public:
    Logical(): var(0) {}
    void set(int x) const { var = x; }
};

class Bitwise {
    int var;

public:
    Bitwise(): var(0) {}
    void set(int x) const {
        const_cast<Bitwise*>(this)->var = x;
    }
};

const Logical logical; // Not put in read-only.
const Bitwise bitwise; // Likely put in read-only.

int main(void)
{
    logical.set(5); // Well defined.
    bitwise.set(5); // Undefined.
}

请参阅其他答案了解更多细节,但我想强调的是,这不仅仅是为了类型安全,而且它会影响编译结果。

当你重写一个const虚函数并想要修改该函数中的子类成员变量时,mutable可以很方便。在大多数情况下,您不希望更改基类的接口,因此必须使用自己的可变成员变量。

使用可变的一个最好的例子是,在深度复制中。在复制构造函数中,我们发送const &obj作为参数。因此,新创建的对象将是常量类型。如果我们想要改变这个新创建的const对象中的成员(大多数情况下我们不会改变,在极少数情况下我们可能会改变),我们需要将它声明为mutable。

可变存储类只能用于类的非静态非const数据成员。类的Mutable数据成员可以被修改,即使它是声明为const的对象的一部分。

class Test
{
public:
    Test(): x(1), y(1) {};
    mutable int x;
    int y;
};

int main()
{
    const Test object;
    object.x = 123;
    //object.y = 123;
    /* 
    * The above line if uncommented, will create compilation error.
    */   

    cout<< "X:"<< object.x << ", Y:" << object.y;
    return 0;
}

Output:-
X:123, Y:1

在上面的例子中,我们能够改变成员变量x的值,尽管它是声明为const的对象的一部分。这是因为变量x声明为可变的。但是如果你试图修改成员变量y的值,编译器会抛出一个错误。