【问题标题】:When have you used C++ 'mutable' keyword? [closed]你什么时候使用过 C++ 'mutable' 关键字? [关闭]
【发布时间】:2010-12-29 12:21:23
【问题描述】:

您什么时候使用过 C++ mutable 关键字?为什么?我认为我从来没有使用过那个关键字。我知道它用于诸如缓存(或者可能是记忆)之类的事情,但是您曾经需要在什么类别和条件下使用它?

【问题讨论】:

  • volatile vs. mutable in C++ 的可能重复项
  • 你的意思是memoization?看起来很奇怪,这不是“记忆”的错字
  • @acidzombie24 我认为给出的答案在这里非常相关。这就是可能重复的原因。如果不是,它不会被关闭。
  • @acidzombie24 请保持清洁和非滥用
  • @David Heffernan:保持什么清洁?我不会在编程中滥用关键字,因此这个问题:)

标签: c++


【解决方案1】:

有时我使用它来将互斥锁或其他线程同步原语标记为可变,以便通常标记为 const 的访问器/查询方法仍然可以锁定互斥锁。

当您需要检测代码以进行调试或测试时,它有时也很有用,因为检测通常需要从内部查询方法修改辅助数据。

【讨论】:

  • 这个,我发现这是我一直在使用的代码中可变的最常见用途。事实上,我在声明它们时默认使用mutable mutex,而没有考虑过该语言是否需要mutable 关键字。毕竟mutex 不是对象状态的一部分。
  • 这主要是我用它的目的。
【解决方案2】:

在从内部成员计算的对象缓存结果的情况下,我使用了 mutable:

class Transformation
{
    private:
        vec3 translation;
        vec3 scale;
        vec4 rotation;
        mutable mat4 transformation;
        mutable bool changed;
    public:
        Node()
        {
            [...]
            changed = false;
        }
        void set_translation(vec3 _translation)
        {
            translation = _translation;
            changed = true;
        }
        void set_scale(...) ...


        mat4 get_transformation() const
        {
            if(changed)
            {
                 // transformation and changed need to be mutable here
                 transformation = f(translation, scale, rotation); // This take a long time...
                 changed = false;
            }
            return transformation;
        }
};

void apply_tranformation(const Transformation* transfo)
{
    apply(transfo->get_transformation());
}

【讨论】:

    【解决方案3】:

    Google code search 揭示了许多用途。例如,在XTR cryptography 的实现中,使用了可变成员,以便方法可以返回对结果的引用(防止复制)。

    再举一个例子,Webkit 使用它来延迟初始化成员数据(m_lineHeight)。

    【讨论】:

    • 提供的链接已损坏
    【解决方案4】:

    我将mutable 用于按需初始化的类成员,尤其是来自程序外部的数据库或源。这允许“getter”函数按需创建对象,否则它是一个常量方法。

    【讨论】:

      【解决方案5】:

      我在为线程安全锁定互斥锁时使用它。互斥体被标记为可变,因此锁定它的方法可以保持不变。

      【讨论】:

        【解决方案6】:

        在模拟对象中捕获成员变量中 const 函数的参数值。

        class Source
        {
        public:
            virtual ~Source() {}
            virtual std::string read(int count) const=0;
        };
        
        class SourceMock : public Source
        {
        public:
            mutable std::vector<int> arguments;
            std::string read(int count) const {
                arguments.push_back(count);
                return "...";
            }
        };
        
        //TEST....
        SourceMock mock;
        //...
        VERIFY(mock.arguments.size()==2);
        VERIFY(mock.arguments[0]==3);
        //...
        

        【讨论】:

        • +1 很酷的情况。我仍然很难想象什么时候会使用它,但我可以相信这一点。
        【解决方案7】:

        http://msdn.microsoft.com/en-us/library/4h2h0ktk%28v=vs.80%29.aspx 是最好的例子。嘿,我今天学到了一些东西!

        【讨论】:

        • 我知道这很有用,但我仍然想不出我什么时候会这样做(似乎总是有更好的地方放那个)
        • 实际上,我曾多次偶然发现这种情况:首先设计类,使其部分 getter 为 const,然后添加更多代码,这些代码将使用从“const”获得的 Ptr Ptr* Class::getSomeMember() const;"以这种方式,编译器抱怨它“不能在这种情况下使用 const Ptr*”或其他东西。现在我知道如何解决这个问题了:)
        • 链接已损坏。
        【解决方案8】:

        mutable 关键字允许您在 const 上下文中修改变量

        例如:

        class Person {
        private:
              mutable int age;
        
        public:
            Person(int age) : age(age)  {
        
            }
            void setAge(int age) const {
                Person::age = age;
            }
        
            int getAge() const {
                return Person::age;
            }
        };
        
        int main() {
        
            Person person(23);
            std::cout << "Person age " << person.getAge() << std::endl;
            person.setAge(24);
            std::cout << "Person modified age " << person.getAge() << std::endl;
            return 0;
        }
        

        【讨论】:

          【解决方案9】:

          我的模板类实现了引用计数器模式。当它作为带有 const 修饰符的参数传递给函数时,无论如何都可能增加引用。因此,可以使用可变的而不是 const_cast

          【讨论】:

          • 嗯,很有趣。做 YourTemplate 而不是 const YourTemplate 更好吗?那不会解决它吗? +1 反正
          • @acidzombie24 - 如果内部类真的是 const,那是真的,但对于一般用途, 是非常严格的。
          【解决方案10】:

          它可以在许多场景中使用,例如

          Loggerstimingaccess counters

          这些可以在 const 限定的访问器中调用而不改变数据的状态。

          【讨论】:

            【解决方案11】:

            如果在getter方法内(通常是const),也可以使用它,您需要更新存储的返回值。例如,假设您有一个特定的链表实现。对于性能问题,您保留列表的最后计算长度,但在返回长度时,如果列表已被修改,则再次计算它,否则,您返回最后缓存的值。

            class MyLinkedList
            {
            public:
              long getLength() const
              {
                if (lengthIsModified())
                {
                  mLength = ...; // do the computation here
                }
                return mLength;
              }
            private:
              mutable long mLength;
            };
            

            警告:由于列表中的一些特定操作(如合并),始终保持 mLength 最新并不容易。

            【讨论】:

              猜你喜欢
              • 2010-09-06
              • 1970-01-01
              • 2011-03-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多