“可变”是否可以? 除了允许 const 成员函数修改数据成员之外,关键字还有其他用途吗?
不久前,我遇到了一些用 mutable
关键字标记类的数据成员的代码。 据我所知,它只是允许您修改 const
限定的成员方法中的成员:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
这是 this 关键字的唯一用途,还是还有比表面上看起来更多的用途? 此后,我在一个类中使用了这种技术,将 boost::mutex 标记为可变的,允许 const 函数锁定它以实现线程安全原因,但说实话,感觉有点像黑客。
A while ago, I came across some code that marked a data member of a class with the mutable
keyword. As far as I can see it simply allows you to modify a member in a const
-qualified member method:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
Is this the only use of this keyword, or is there more to it than meets the eye? I have since used this technique in a class, marking a boost::mutex
as mutable
, allowing const
functions to lock it for thread-safety reasons, but, to be honest, it feels like a bit of a hack.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
关键字“mutable”实际上是一个保留关键字。通常它用于改变常量变量的值。如果您想要一个 constsnt 具有多个值,请使用关键字 mutable。
The very keyword 'mutable' is actually a reserved keyword.often it is used to vary the value of constant variable.If you want to have multiple values of a constsnt,use the keyword mutable.
我们使用可变的最好的例子之一是在深度复制中。 在复制构造函数中,我们发送 const &obj 作为参数。 因此创建的新对象将是常量类型。 如果我们想要更改(大多数情况下我们不会更改,极少数情况下我们可能会更改)这个新创建的 const 对象中的成员,我们需要将其声明为
mutable
。可变
存储类只能用于类的非静态非常量数据成员。 即使类的可变数据成员是声明为 const 的对象的一部分,也可以对其进行修改。在上面的示例中,我们可以更改成员变量 x 的值,尽管它是声明为 const 的对象的一部分。 这是因为变量
x
被声明为可变的。 但是如果你尝试修改成员变量y
的值,编译器会抛出错误。One of the best example where we use mutable is, in deep copy. in copy constructor we send
const &obj
as argument. So the new object created will be of constant type. If we want to change (mostly we won't change, in rare case we may change) the members in this newly created const object we need to declare it asmutable
.mutable
storage class can be used only on non static non const data member of a class. Mutable data member of a class can be modified even if it's part of an object which is declared as const.In the above example, we are able to change the value of member variable
x
though it's part of an object which is declared as const. This is because the variablex
is declared as mutable. But if you try to modify the value of member variabley
, compiler will throw an error.当您重写 const 虚函数并想要修改该函数中的子类成员变量时,可变可以很方便。 在大多数情况下,您不想更改基类的接口,因此您必须使用自己的可变成员变量。
The mutable can be handy when you are overriding a const virtual function and want to modify your child class member variable in that function. In most of the cases you would not want to alter the interface of the base class, so you have to use mutable member variable of your own.
在某些情况下(例如设计不佳的迭代器),类需要保留计数或其他一些附带值,这并不会真正影响类的主要“状态”。 这是我最常看到使用可变的地方。 如果没有可变性,您将被迫牺牲设计的整体稳定性。
对我来说,大多数时候这感觉就像是黑客攻击。 在极少数情况下很有用。
In some cases (like poorly designed iterators), the class needs to keep a count or some other incidental value, that doesn't really affect the major "state" of the class. This is most often where I see mutable used. Without mutable, you'd be forced to sacrifice the entire const-ness of your design.
It feels like a hack most of the time to me as well. Useful in a very very few situations.
在创建用于类测试目的的存根时,可变关键字非常有用。 您可以存根 const 函数,并且仍然能够增加(可变)计数器或添加到存根中的任何测试功能。 这使得存根类的接口保持完整。
The mutable keyword is very useful when creating stubs for class test purposes. You can stub a const function and still be able to increase (mutable) counters or whatever test functionality you have added to your stub. This keeps the interface of the stubbed class intact.
经典示例(如其他答案中提到的)以及迄今为止我所见过的 mutable 关键字的唯一情况是用于缓存复杂的 Get 方法的结果,其中缓存被实现为类的数据成员,而不是方法中的静态变量(出于在多个函数之间共享或简单清洁的原因)。
一般来说,使用
mutable
关键字的替代方法通常是方法中的静态变量或const_cast
技巧。另一个详细解释在这里。
The classic example (as mentioned in other answers) and the only situation I have seen the
mutable
keyword used in so far, is for caching the result of a complicatedGet
method, where the cache is implemented as a data member of the class and not as a static variable in the method (for reasons of sharing between several functions or plain cleanliness).In general, the alternatives to using the
mutable
keyword are usually a static variable in the method or theconst_cast
trick.Another detailed explanation is in here.
Mutable 将类的
const
的含义从按位 const 更改为逻辑 const。这意味着具有可变成员的类不再是按位常量,并且将不再出现在可执行文件的只读部分中。
此外,它通过允许 const 成员函数在不使用 const_cast 的情况下更改可变成员来修改类型检查。
有关更多详细信息,请参阅其他答案,但我想强调它不仅仅是为了类型安全,而且它会影响编译结果。
Mutable changes the meaning of
const
from bitwise const to logical const for the class.This means that classes with mutable members are longer be bitwise const and will no longer appear in read-only sections of the executable.
Furthermore, it modifies type-checking by allowing
const
member functions to change mutable members without usingconst_cast
.See the other answers for more details but I wanted to highlight that it isn't merely for type-saftey and that it affects the compiled result.
你对它的使用并不是一种 hack,尽管像 C++ 中的许多东西一样,对于那些不想一路返回并标记不应该标记的东西的懒惰程序员来说,可变可以作为非 const 是 const。
Your use of it isn't a hack, though like many things in C++, mutable can be hack for a lazy programmer who doesn't want to go all the way back and mark something that shouldn't be const as non-const.
mutable 主要用于类的实现细节。 类的用户不需要知道它,因此他认为“应该”的方法是 const 即可。 您的互斥体可变的示例是一个很好的规范示例。
mutable is mainly used on an implementation detail of the class. The user of the class doesn't need to know about it, therefore method's he thinks "should" be const can be. Your example of having a mutex be mutable is a good canonical example.
对于逻辑上对用户来说无状态的事物(因此在公共类的 API 中应该有“const”getter)但在底层实现(.cpp 中的代码)中不是无状态的,请使用“可变”。
我最常使用它的情况是无状态“普通旧数据”成员的延迟初始化。 也就是说,在少数情况下,它是理想的,因为此类成员的构建(处理器)或携带(内存)都很昂贵,并且该对象的许多用户永远不会要求它们。 在这种情况下,您希望在后端进行惰性构建以提高性能,因为构建的 90% 的对象根本不需要构建它们,但您仍然需要提供正确的无状态 API 供公共使用。
Use "mutable" when for things that are LOGICALLY stateless to the user (and thus should have "const" getters in the public class' APIs) but are NOT stateless in the underlying IMPLEMENTATION (the code in your .cpp).
The cases I use it most frequently are lazy initialization of state-less "plain old data" members. Namely, it is ideal in the narrow cases when such members are expensive to either build (processor) or carry around (memory) and many users of the object will never ask for them. In that situation you want lazy construction on the back end for performance, since 90% of the objects built will never need to build them at all, yet you still need to present the correct stateless API for public consumption.
嗯,是的,这就是它的作用。 我将它用于通过不会逻辑改变类状态的方法修改的成员 - 例如,通过实现缓存来加速查找:
现在,您必须小心使用它 - 并发问题是一个大问题,因为如果仅使用 const 方法,调用者可能会认为它们是线程安全的。 当然,修改可变数据不应该以任何显着的方式改变对象的行为,我给出的示例可能会违反这一点,例如,如果预期将更改写入磁盘将立即对应用程序可见。
Well, yeah, that's what it does. I use it for members that are modified by methods that do not logically change the state of a class - for instance, to speed up lookups by implementing a cache:
Now, you must use this with care - concurrency issues are a big concern, as a caller might assume that they are thread safe if only using
const
methods. And of course, modifyingmutable
data shouldn't change the behavior of the object in any significant fashion, something that could be violated by the example i gave if, for instance, it was expected that changes written to disk would be immediately visible to the app.当类内部有一个变量仅在该类中用于表示互斥锁或锁等信号时,将使用可变。 该变量不会更改类的行为,但为了实现类本身的线程安全性是必需的。 因此,如果没有“mutable”,您将无法拥有“const”函数,因为需要在外界可用的所有函数中更改此变量。 因此,引入 mutable 是为了使成员变量即使是 const 函数也可写。
Mutable is used when you have a variable inside the class that is only used within that class to signal things like for example a mutex or a lock. This variable does not change the behaviour of the class, but is necessary in order to implement thread safety of the class itself. Thus if without "mutable", you would not be able to have "const" functions because this variable will need to be changed in all functions that are available to the outside world. Therefore, mutable was introduced in order to make a member variable writable even by a const function.
当您推断允许修改其他常量函数中的数据时,
mutable
确实存在。目的是您可能有一个对对象的内部状态“不执行任何操作”的函数,因此您将函数标记为 const,但您可能确实需要修改不影响其正确功能的方式。
该关键字可以充当编译器的提示——理论上编译器可以将常量对象(例如全局对象)放置在标记为只读的内存中。
mutable
的存在暗示不应该这样做。以下是声明和使用可变数据的一些正当理由:
mutable
does exist as you infer to allow one to modify data in an otherwise constant function.The intent is that you might have a function that "does nothing" to the internal state of the object, and so you mark the function
const
, but you might really need to modify some of the objects state in ways that don't affect its correct functionality.The keyword may act as a hint to the compiler -- a theoretical compiler could place a constant object (such as a global) in memory that was marked read-only. The presence of
mutable
hints that this should not be done.Here are some valid reasons to declare and use mutable data:
mutable boost::mutex
is perfectly reasonable.它在隐藏内部状态(例如缓存)的情况下非常有用。 例如:
然后您可以让一个
const HashTable
对象仍然使用其lookup()
方法,该方法会修改内部缓存。It's useful in situations where you have hidden internal state such as a cache. For example:
And then you can have a
const HashTable
object still use itslookup()
method, which modifies the internal cache.您对 boost::mutex 的使用正是该关键字的用途。 另一个用途是用于内部结果缓存以加速访问。
基本上,“可变”适用于不影响对象的外部可见状态的任何类属性。
在您问题的示例代码中,如果 did_ 的值影响外部状态,则 mutable 可能不合适,这取决于 ... 中的内容; 部分。
Your use with boost::mutex is exactly what this keyword is intended for. Another use is for internal result caching to speed access.
Basically, 'mutable' applies to any class attribute that does not affect the externally visible state of the object.
In the sample code in your question, mutable might be inappropriate if the value of done_ affects external state, it depends on what is in the ...; part.
Mutable 用于将特定属性标记为可在
const
方法中修改。 这是它的唯一目的。 使用它之前请仔细考虑,因为如果您更改设计而不是使用mutable
,您的代码可能会更干净且更具可读性。http://www.highprogrammer.com/alan/rants/mutable.html
作者给出的示例包括缓存和临时调试变量。
Mutable is for marking specific attribute as modifiable from within
const
methods. That is its only purpose. Think carefully before using it, because your code will probably be cleaner and more readable if you change the design rather than usemutable
.http://www.highprogrammer.com/alan/rants/mutable.html
Examples the author gives include caching and temporary debugging variables.
mutable
关键字是一种刺破覆盖在对象上的const
面纱的方法。 如果您有一个指向对象的 const 引用或指针,则您不能以任何方式修改该对象,除了将其标记为可变
的时间和方式。使用
const
引用或指针,您将受到以下限制:const
的方法。mutable
异常使得您现在可以编写或设置标记为mutable
的数据成员。 这是唯一外部可见的差异。在内部,您可见的那些
const
方法也可以写入标记为mutable
的数据成员。 本质上,常量面纱已被全面刺破。 API 设计者完全有责任确保mutable
不会破坏const
概念,并且仅在有用的特殊情况下使用。mutable
关键字很有帮助,因为它清楚地标记了受这些特殊情况影响的数据成员。实际上,您可以在整个代码库中大量使用
const
(您本质上是想用const
“疾病”“感染”您的代码库)。 在这个世界中,指针和引用都是 const,几乎没有例外,从而产生更容易推理和理解的代码。 对于一个有趣的题外话,请查阅“引用透明度”。如果没有
mutable
关键字,您最终将被迫使用const_cast
来处理它允许的各种有用的特殊情况(缓存、引用计数、调试数据等)。 不幸的是,const_cast
比mutable
更具破坏性,因为它强制 API 客户端 破坏对象的const
保护他(她)正在使用。 此外,它还会导致广泛的 const 破坏:使用 const 指针或引用进行 const_cast 允许对可见成员进行不受约束的写入和方法调用访问。 相比之下,mutable
要求 API 设计者对const
异常进行细粒度控制,通常这些异常隐藏在私有操作的const
方法中。数据。(注意,我多次提到数据和方法可见性。我谈论的是标记为公共与私有或受保护的成员,这是讨论的完全不同类型的对象保护此处。)
The
mutable
keyword is a way to pierce theconst
veil you drape over your objects. If you have a const reference or pointer to an object, you cannot modify that object in any way except when and how it is markedmutable
.With your
const
reference or pointer you are constrained to:const
.The
mutable
exception makes it so you can now write or set data members that are markedmutable
. That's the only externally visible difference.Internally those
const
methods that are visible to you can also write to data members that are markedmutable
. Essentially the const veil is pierced comprehensively. It is completely up to the API designer to ensure thatmutable
doesn't destroy theconst
concept and is only used in useful special cases. Themutable
keyword helps because it clearly marks data members that are subject to these special cases.In practice you can use
const
obsessively throughout your codebase (you essentially want to "infect" your codebase with theconst
"disease"). In this world pointers and references areconst
with very few exceptions, yielding code that is easier to reason about and understand. For a interesting digression look up "referential transparency".Without the
mutable
keyword you will eventually be forced to useconst_cast
to handle the various useful special cases it allows (caching, ref counting, debug data, etc.). Unfortunatelyconst_cast
is significantly more destructive thanmutable
because it forces the API client to destroy theconst
protection of the objects (s)he is using. Additionally it causes widespreadconst
destruction:const_cast
ing a const pointer or reference allows unfettered write and method calling access to visible members. In contrastmutable
requires the API designer to exercise fine grained control over theconst
exceptions, and usually these exceptions are hidden inconst
methods operating on private data.(N.B. I refer to to data and method visibility a few times. I'm talking about members marked as public vs. private or protected which is a totally different type of object protection discussed here.)
它允许区分按位常量和逻辑常量。 逻辑常量是指对象不会以通过公共接口可见的方式更改,例如锁定示例。 另一个例子是一个类,它在第一次请求时计算一个值,并缓存结果。
由于 c++11
mutable
可用于 lambda 来表示通过值捕获的内容是可修改的(默认情况下它们是不可修改的):It allows the differentiation of bitwise const and logical const. Logical const is when an object doesn't change in a way that is visible through the public interface, like your locking example. Another example would be a class that computes a value the first time it is requested, and caches the result.
Since c++11
mutable
can be used on a lambda to denote that things captured by value are modifiable (they aren't by default):