没有'可变的'关键词有其他任何目的超过允许的变量进行修改,以const功能?

StackOverflow https://stackoverflow.com/questions/105014

  •  01-07-2019
  •  | 
  •  

不久前我遇到了一些代码,标志着一件可变的一个类的 mutable 关键词。尽我所能看到它只是让你修改的一个变量 const 方法:

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

这是唯一使用的这个关键字或者是有更重要的是它满足眼睛?因为我已经用这种技术中的一类,标志着一个 boost::mutex 作为可变的允许 const 功能要把它锁线安全原因,但,说实话,感觉就像一位中的一个黑客。

有帮助吗?

解决方案

它允许区分按位const和逻辑const。逻辑const是指对象不会以通过公共接口可见的方式更改,例如锁定示例。另一个例子是一个在第一次请求时计算值的类,并缓存结果。

因为可以在lambda上使用c ++ 11 mutable 来表示按值捕获的内容是可修改的(默认情况下不是这样):

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

其他提示

mutable 关键词是一种方法来刺穿 const 面纱你披在你的对象。如果你有一个常量基准或指针指向一个目的,你不能修改,目的在任何方式 除了 当时以及它是如何标记 mutable.

与你的 const 基准或指你的约束:

  • 只读取任何可见的数据成员
  • 允许叫唯一方法作为标记 const.

mutable 异常使得所以你现在可以写入或集的数据成员的标记 mutable.这是唯一的外部可见差异。

内部那些 const 方法都可以看到你也可以写信给数据成员的标记 mutable.基本上const的面纱被刺穿全面。它是完全由API设计师来确保 mutable 不摧毁 const 概念,并只用在用特殊情况。的 mutable 关键字的帮助,因为它清楚地标记的数据成员都受到这些特殊情况。

在实践中可以使用 const 强在你的代码(你基本上想到"感染"你的代码用 const "疾病").在这个世界上的指针和参考文献 const 除了极少数例外情况以外,产生的代码,更容易理解和理解。对于一个有趣的题外话看看"参照透明度"。

没有的 mutable 关键字会最终被迫使用 const_cast 到处理的各种有用的特殊情况下允许(缓存,ref计数、调试的数据,等等)。不幸的是 const_cast 明显地更具破坏性比 mutable 因为它的部队API 客户 摧毁 const 保护的对象(s)他是使用。此外,它导致的普遍 const 破坏: const_cast荷兰国际集团一个常数指针或基准允许自由写和方法,呼叫接可见的成员。与此相反 mutable 需要API设计师行使细的控制 const 例外情况,这些例外通常被隐藏在 const 方法工作上的私人数据。

(N.B.我指的是对数据和方法 可见性 几倍。我说的是关于成员标志着为与公众私人或保护,它是一个完全不同类型的物保护的讨论 在这里,.)

你使用的增强::互斥正是这个关键词。另一种用于内部的结果的缓存的速度访问。

基本上,'可变的'适用于任何类属性,不会影响外部可见的国家的对象。

在这样的代码,在你的问题、可变可能是不合适的价值done_影响的外部国家,这取决于什么是...;部分。

Mutable用于将特定属性标记为可从 const 方法中修改。这是它的唯一目的。在使用之前要仔细考虑,因为如果更改设计而不是使用 mutable ,您的代码可能会更清晰,更易读。

http://www.highprogrammer.com/alan/rants/mutable.html

  

所以,如果上述疯狂不是什么   可变的是,它是什么?这里的   微妙的情况:可变的是为了   对象在逻辑上的情况   不变,但在实践中需要   更改。这些案件很少见   之间,但他们存在。

作者提供的示例包括缓存和临时调试变量。

在隐藏内部状态(如缓存)的情况下,它非常有用。例如:

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()方法,它修改了内部缓存。

嗯,是的,这就是它的作用。我将它用于那些不通过逻辑更改类状态的方法修改的成员 - 例如,通过实现缓存来加速查找:

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;
};

现在,您必须小心使用它 - 并发问题是一个大问题,因为如果仅使用 const 方法,调用者可能会认为它们是线程安全的。当然,修改 mutable 数据不应该以任何重要的方式改变对象的行为,例如,如果我预期改变写入的话,我可以违反这个例子。磁盘将立即显示给应用程序。

mutable 确实存在你推断出,以允许一个修改的数据,在另一个恒定的功能。

意图是,你可能会有功能"无"的国家内部的对象,所以你标记的功能 const, 但你可能真的需要修改的一些对象国家的方式,不影响其正确的功能。

关键词可以作为一个暗示来编译器--一个理论上编译器可能恒定的对象(例如一个全球性的)存储器标记只读。存在的 mutable 提示,这不应该被完成。

这里有一些合理的理由来宣布和使用的可变数据:

  • 线的安全。声明 mutable boost::mutex 是完全合理的。
  • 统计数据。计算数量的呼吁函,鉴于一些或所有其参数。
  • 性记忆化.计算一些昂贵的回答,然后储存供日后参考,而不是重新计算一次。

当在类中有一个变量时,使用Mutable,该变量仅在该类中用于表示诸如互斥锁或锁之类的信号。此变量不会更改类的行为,但是为了实现类本身的线程安全性是必需的。因此,如果没有“可变”,你将无法拥有“const”。函数,因为需要在外部世界可用的所有函数中更改此变量。因此,引入了mutable,以便使成员变量甚至可以通过const函数进行写入。

  

指定的mutable通知编译器和读者它   是安全的,并期望可以在const中修改成员变量   成员函数。

mutable主要用于类的实现细节。该类的用户不需要知道它,因此他认为方法是“应该”。是const可以。你的互斥量可变的例子是一个很好的规范例子。

你对它的使用并不是一种破解,虽然像C ++中的许多东西一样,可变的可以成为一个懒惰程序员的黑客,他们不想一直回头并标记出一些东西。不应该是const为非const。

使用“可变”的什么时候对于用户来说是LOGICALLY无状态的(因此在公共类'API中应该有“const”getter)但在底层的IMPLEMENTATION(你的.cpp中的代码)中不是无状态的。

我最经常使用它的情况是无状态“普通旧数据”的延迟初始化。成员。也就是说,在这种成员构建(处理器)或随身携带(存储器)昂贵的情况下,它是理想的,并且对象的许多用户永远不会要求它们。在这种情况下,你需要在后端进行延迟构造以提高性能,因为90%的构建对象根本不需要构建它们,但是你仍然需要提供正确的无状态API供公众使用。

Mutable将 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.
}

有关更多详细信息,请参阅其他答案,但我想强调它不仅仅是针对type-saftey而且会影响编译结果。

在某些情况下(如设计不佳的迭代器),类需要保持计数或其他偶然值,这并不会真正影响主要的“状态”。班上的。这通常是我看到可变使用的地方。如果没有可变性,你将被迫牺牲整个设计的整体性。

对我来说,大部分时间感觉像是黑客。在极少数情况下很有用。

经典示例(在其他答案中提到)和我见过的唯一情况是到目前为止使用的 mutable 关键字,用于缓存复杂的 Get 方法,其中缓存实现为类的数据成员而不是方法中的静态变量(出于在多个函数之间共享或清除原因的原因)。

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

另一个详细解释是此处

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

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

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

mutable 存储类只能用于类的非静态非const数据成员。即使它是声明为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 的值,编译器将抛出错误。

非常关键字'mutable'实际上是一个保留的keyword.often它用于改变常量变量的值。如果你想拥有constsnt的多个值,请使用关键字mutable。

//Prototype 
class tag_name{
                :
                :
                mutable var_name;
                :
                :
               };   
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top