【问题标题】:Is it correct to have a const function which modified a 'scratchpad' variable?有一个修改“便签本”变量的 const 函数是否正确?
【发布时间】:2016-05-15 12:52:32
【问题描述】:

我将描述问题。我有一个带有 API 的类,它调用大量的类成员函数层次结构来执行一些逻辑。现在,我更新了逻辑,因此层次结构中的每个函数都需要一个额外的参数(API 没有改变)。

一个想法 - 我可以在类中添加一个“scrathpad”成员,而不是为每个方法添加一个额外的参数,即一个仅用于临时计算的变量,并且仅在时间范围内“有效” API 调用,调用完成后就是“垃圾”。

例子:

void A::api()
{
   scratch_pad = get_some_value_once();
   foo1();
}
void A::foo1() { ...; foo2(); }
void A::foo2() { ...; foo3(); }
...
void A::fooN() /* Called 100000000 times */
{ 
     ...; 
     // Do something with scratch_pad.
     // I would realy like to avoid adding 'scratch_pad' parameter to all the foos().
}

这是一种有效的方法吗?

如果我的 API 声明为 const,它仍然有效吗?

【问题讨论】:

  • WTH 是 "scratchpad" 变量吗?你能用一些(伪)代码示例来说明这一点吗?
  • 如果不改变物体的可观察状态,我觉得没问题。
  • “现在,我更新了逻辑,因此层次结构中的每个函数都需要一个额外的参数(API 没有改变)。” 听起来应该使用继承来替换一个接口定义,但实际上不可能从你不清楚的上下文中分辨出来。
  • 请注意,如果你这样做,它会让你的类不是线程安全的,并且添加同步会使其变慢。
  • 为什么不总是调用 get_some_value_once 并在 that 函数中隐藏记忆逻辑?

标签: c++ oop abstraction


【解决方案1】:

请不要这样做。

您正在使您的对象实例更大(占用更多内存),即使您只需要内部函数调用的生命周期内的变量。

您正在使您的函数本质上是多线程不安全的,或者在以前不需要锁定时需要锁定。

您使代码本质上不那么明显/可维护。

如果您想在 API 调用中使用 const,那么您需要开始添加可变变量(呃)。

改为使用局部变量。查看 Basilevs 的答案,了解一种方法。

【讨论】:

    【解决方案2】:

    一般来说,当成员不属于类的可观察状态时,在 const 方法中更改成员的值是可以的。

    您必须使用 mutable 关键字标记您的“便签本”成员。
    否则,如果你在 const 方法中分配给它,你会得到一个编译错误。

    查看 isocpp 常见问题解答 - https://isocpp.org/wiki/faq/const-correctness#mutable-data-members

    【讨论】:

      【解决方案3】:

      类成员用作临时存储的主要问题是线程安全。当从另一个线程调用方法时,内部数据的成员存储将以不可预知的方式重用。它还引入了方法之间的隐藏耦合。

      实际上,您需要的是具有 API 调用生命周期的附加(可能是不可变的)状态。在 C++ 中处理状态和生命周期的常用方法是使用类。

      我建议将新参数提取到新的不可变类,将所需的方法移动到新类并让 API 实现创建此类并调用它们。

      代替:

      class API {
         private:
         int state;
         void implement() {
           cout << state << endl;
         }
         public:
         void execute() {
            state = 1;
            implement();
         }
      }
      

      做:

      class State {
         int value;
         public:
         State(int valueArg): value(valueArg) {}
         void implement() const {
           cout << state << endl;
         }
      
      }
      
      class API {
         public:
         void execute() const {
            State(1).implement();
         }
      }
      

      【讨论】:

      • 这比使用建议的“便签本”变量方法要好得多。不过,我建议将 State 设为 API 的私有内部类。
      猜你喜欢
      • 2011-11-15
      • 1970-01-01
      • 2017-01-23
      • 2012-02-27
      • 2015-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多