Rob*_*Rob 511 c++ mutable keyword
前段时间我遇到了一些用mutable关键字标记类的成员变量的代码.据我所知,它只是允许您修改const方法中的变量:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
Run Code Online (Sandbox Code Playgroud)
这是这个关键字的唯一用途,还是有更多的东西比它的眼睛?我已经在一个类中使用了这个技术,标记为一个boost::mutex可变的允许const函数为了线程安全的原因锁定它,但是,说实话,这感觉有点像黑客.
Kei*_*thB 341
它允许区分按位const和逻辑const.逻辑const是指对象不会以通过公共接口可见的方式更改,例如锁定示例.另一个例子是一个在第一次请求时计算值的类,并缓存结果.
因为mutable可以在lambda上使用c ++ 11 来表示按值捕获的内容是可修改的(默认情况下不是这样):
int x = 0;
auto f1 = [=]() mutable {x = 42;}; // OK
auto f2 = [=]() {x = 42;}; // Error: a by-value capture cannot be modified in a non-mutable lambda
Run Code Online (Sandbox Code Playgroud)
Dan*_*n L 134
该mutable关键字是刺破的方式const,你悬垂在你的对象面纱.如果你有一个const引用或指向对象的指针,你不能以任何方式修改该对象,除非它被标记的时间和方式mutable.
使用您的const引用或指针,您将被限制为:
const.此mutable异常使您现在可以编写或设置标记的数据成员mutable.这是唯一外部可见的差异.
在内部const,您可以看到的方法也可以写入标记的数据成员mutable.从本质上讲,全面穿孔.完全取决于API设计者,以确保mutable不破坏const概念,仅用于有用的特殊情况.该mutable关键字的帮助,因为它清楚地标志着数据成员都受到这些特殊情况.
在实践中,您可以const在整个代码库中使用(您基本上希望用const"疾病" "感染"您的代码库).在这个世界中,指针和引用const几乎没有例外,产生的代码更容易推理和理解.对于一个有趣的题外话,请查看"参考透明度".
如果没有mutable关键字,您最终将被迫使用它const_cast来处理它允许的各种有用的特殊情况(缓存,引用计数,调试数据等).不幸的const_cast是mutable,它的破坏性明显大于因为它迫使API 客户端破坏const他正在使用的对象的保护.此外,它会导致广泛的const破坏:const_castconst指针或引用允许对可见成员进行不受约束的写入和方法调用访问.相反,mutable要求API设计者对const异常进行细粒度控制,通常这些异常隐藏在const对私有数据进行操作的方法中.
(注:我指的是对数据和方法的可视性几次.我讲的成员标记为公共与私有或保护的是讨论一个完全不同类型的对象的保护这里.)
Fra*_*rba 75
您对boost :: mutex的使用正是此关键字的用途.另一个用途是用于内部结果缓存以加快访问速度.
基本上,'mutable'适用于不影响对象外部可见状态的任何类属性.
在您的问题的示例代码中,如果done_的值影响外部状态,则可变性可能是不合适的,这取决于...中的内容; 部分.
Joh*_*kin 35
Mutable用于将特定属性标记为可从const方法内修改.这是它的唯一目的.在使用它之前要仔细考虑,因为如果您更改设计而不是使用,您的代码可能会更清晰,更易读mutable.
http://www.highprogrammer.com/alan/rants/mutable.html
因此,如果上述疯狂不是可变的,它是什么?这是一个微妙的案例:mutable是指对象在逻辑上不变的情况,但实际上需要改变.这些案例很少见,但它们存在.
作者提供的示例包括缓存和临时调试变量.
Ada*_*eld 31
它在您隐藏内部状态(如缓存)的情况下很有用.例如:
class HashTable
{
...
public:
string lookup(string key) const
{
if(key == lastKey)
return lastValue;
string value = lookupInternal(key);
lastKey = key;
lastValue = value;
return value;
}
private:
mutable string lastKey, lastValue;
};
然后你可以让一个const HashTable对象仍然使用它的lookup()方法,它修改了内部缓存.
mutable 当你推断允许一个人修改其他常数函数中的数据时确实存在.
目的是你可能有一个对对象的内部状态"什么也不做"的函数const,所以你标记了这个函数,但是你可能真的需要修改一些对象状态而不影响它的正确功能.
关键字可以作为编译器的提示 - 理论编译器可以将一个常量对象(例如全局)放在标记为只读的内存中.的存在mutable暗示,这不应该做的.
以下是声明和使用可变数据的一些正当理由:
mutable boost::mutex是完全合理的.嗯,是的,这就是它的作用.我将它用于通过不在逻辑上改变类状态的方法修改的成员- 例如,通过实现缓存来加速查找:
class CIniWrapper
{
public:
CIniWrapper(LPCTSTR szIniFile);
// non-const: logically modifies the state of the object
void SetValue(LPCTSTR szName, LPCTSTR szValue);
// const: does not logically change the object
LPCTSTR GetValue(LPCTSTR szName, LPCTSTR szDefaultValue) const;
// ...
private:
// cache, avoids going to disk when a named value is retrieved multiple times
// does not logically change the public interface, so declared mutable
// so that it can be used by the const GetValue() method
mutable std::map<string, string> m_mapNameToValue;
};
Run Code Online (Sandbox Code Playgroud)
现在,您必须小心使用它 - 并发问题是一个大问题,因为调用者可能会认为如果只使用const方法它们是线程安全的.当然,修改mutable数据不应该以任何重要的方式改变对象的行为,例如,如果预期写入磁盘的更改将立即对应用程序可见,我可能会违反该示例.
如果在类中只有一个变量用于表示诸如互斥锁或锁之类的信号,则使用Mutable.此变量不会更改类的行为,但是为了实现类本身的线程安全性是必需的.因此,如果没有"可变",您将无法拥有"const"函数,因为需要在外部世界可用的所有函数中更改此变量.因此,引入了mutable,以便使成员变量甚至可以通过const函数进行写入.
指定的mutable通知编译器和读者它是安全的并且期望可以在const成员函数内修改成员变量.
小智 5
对于对用户来说逻辑上无状态的事物(因此在公共类的 API 中应该有“const”getter)但在底层 IMPLEMENTATION(您的 .cpp 中的代码)中不是无状态的,请使用“可变”。
我最常使用它的情况是无状态“纯旧数据”成员的延迟初始化。也就是说,当这些成员的构建(处理器)或携带(内存)成本很高并且对象的许多用户永远不会要求它们时,它是理想的。在这种情况下,您需要在后端进行延迟构建以提高性能,因为 90% 的构建对象根本不需要构建它们,但您仍然需要提供正确的无状态 API 以供公共使用。
constMutable 将类的含义从按位 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.
}
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请参阅其他答案,但我想强调它不仅仅是为了类型安全,而且它会影响编译结果。
| 归档时间: |
|
| 查看次数: |
212392 次 |
| 最近记录: |