a'的正确替代方案;可变函数&x27;在c++; 当C++中的类中打包算法时,经常会遇到const正确性问题。我觉得我想要一个可变函数,尽管这是不允许的。有人能告诉我如何实现下面的类吗

a'的正确替代方案;可变函数&x27;在c++; 当C++中的类中打包算法时,经常会遇到const正确性问题。我觉得我想要一个可变函数,尽管这是不允许的。有人能告诉我如何实现下面的类吗,c++,mutable,C++,Mutable,下面是我想写的代码 函数run()不应是 const函数,因为它更改了 数据 函数get_result()应该 是一个常量函数(就用户而言),因为它返回 数据 但是,如果用户请求结果而不调用run(),我希望get_result()函数运行该算法。这破坏了常量的正确性,因为我有一个常量函数调用一个非常量函数 class operate_on_data { std::vector<double> m_data; // the data to modify bool m_c

下面是我想写的代码

  • 函数run()不应是 const函数,因为它更改了 数据
  • 函数get_result()应该 是一个常量函数(就用户而言),因为它返回 数据
但是,如果用户请求结果而不调用run(),我希望get_result()函数运行该算法。这破坏了常量的正确性,因为我有一个常量函数调用一个非常量函数

class operate_on_data
{
  std::vector<double> m_data;  // the data to modify
  bool m_completed;  // check to see if the function run() has been called
public:
  operate_on_data(std::vector<double> data)
    : m_data(data), m_completed(false) {}  //initialise
  void run() //I don't want this function to be const  
  {
    //The algorithm goes here - it alters m_data.
    m_completed = true;  //the algorithm has been run
  }
  std::vector<double> get_result() const //I want this function to be const
  {
    /*The following breaks const correctness because 
      I am calling a non-const function from a const function
      - but this feels like the right thing to do ... */ 
    if (!m_completed) run();  //run the algorithm if it has not run already
    return m_data; //return
  }
};
类对数据进行操作
{
std::vector m_data;//要修改的数据
bool m_completed;//检查函数run()是否已被调用
公众:
对数据进行操作(标准::矢量数据)
:m_data(data),m_completed(false){}//初始化
void run()//我不希望此函数为常量
{
//算法在这里——它改变m_数据。
m_completed=true;//算法已运行
}
std::vector get_result()const//我希望此函数为const
{
/*以下内容破坏了常量的正确性,因为
我正在从常量函数调用非常量函数
-但这感觉是正确的做法…*/
if(!m_completed)run();//如果算法尚未运行,请运行该算法
返回m_数据;//返回
}
};
编译上述类的唯一方法是

  • 使run()常量,并使m_data和m_completed可变。这是可行的,但在概念上是错误的,因为run()显然会更改数据
  • 使get_result()不是常量函数。这似乎也是错误的,因为用户希望这个函数是一个简单的返回,因此是常量
  • 将run()函数放入get_result()const函数中,并使数据变量可变
我的理解是,mutable关键字是为这些选项中的第三个选项设计的,其中的实现需要更改数据,但用户合理地期望一个简单的返回,因此需要const函数

class operate_on_data
{
  std::vector<double> m_data;  // the data to modify
  bool m_completed;  // check to see if the function run() has been called
public:
  operate_on_data(std::vector<double> data)
    : m_data(data), m_completed(false) {}  //initialise
  void run() //I don't want this function to be const  
  {
    //The algorithm goes here - it alters m_data.
    m_completed = true;  //the algorithm has been run
  }
  std::vector<double> get_result() const //I want this function to be const
  {
    /*The following breaks const correctness because 
      I am calling a non-const function from a const function
      - but this feels like the right thing to do ... */ 
    if (!m_completed) run();  //run the algorithm if it has not run already
    return m_data; //return
  }
};
但是,我不想做最后一个选择,因为我希望用户能够准确地选择何时更改数据。但是,他们可能会忘记调用run(),因此如果他们请求结果而不调用run(),我想强制算法。我想让run()可变,但我不允许这样做


编写这样一个类的正确方法是什么?

只需在运行算法之前将获取结果作为错误(接口的一部分)。然后将工作与结果分开,使两者都能正确地表示其常数。如果在运行算法之前试图调用get方法,以向客户端表明他们做错了什么,那么get方法可能会抛出。

我认为您的问题是语义问题,而不是语法问题

在我看来,在不首先调用
run()
的情况下请求结果是一个错误,应该会导致异常

如果这不是一个错误并且确实是可能的,我认为首先让
run()
没有任何意义,所以干脆放弃它,在(非常量)
get\u result()
中做所有的工作。如果
get\u result()
实际上可能会更改数据,那么它不是常量。如果希望它是常量,不要调用
run()
,而是抛出异常


您应该对缓存数据使用
mutable
,即不会更改实例状态且仅出于性能原因而存储的数据。

如果出现这种情况,我可能会抛出异常

然而,你可能会侥幸逃脱

if (!m_completed) (const_cast <operate_on_data *> (this))->run();
if(!m_completed)(const_cast(this))->run();

但是,如果在实际定义为
const
operation\u data
实例上调用
get\u result
,则您进入拉拉乐园。

一些抽象的注释可能有助于您澄清问题:

  • const
    方法是那些不修改对象概念“状态”的方法
  • 非常量方法就是这样做的方法
  • 此外,
    mutable
    字段是针对每个对象的字段,但不被视为对象概念状态的一部分(如一些缓存的值,这些值会被延迟计算并记住)
问题可能是
对数据进行操作
可能不是一个定义良好的类。“对数据操作”类的对象是什么?这个对象的“状态”是什么?什么不是?这听起来很尴尬(至少对我来说)——对某些设计的描述听起来很尴尬,这可能意味着违反直觉的设计

我的想法是,您将“操作”和“操作结果”的不同概念保留在一个奇怪的类中,这会导致混淆。

使run()常数,并使m_数据和m_完成可变。这是可行的,但在概念上是错误的,因为run()显然会更改数据

事实上不是这样。事实上,你的类中的变量是被改变的,但是你永远也无法证明这一点。调用run()不会更改用户能够从类接口检索到的任何内容。如果您无法检索有关此类更改的任何信息,那么您就不可能演示该更改。这不仅仅是一个语义问题,它直接涉及到“可变”关键字的整个要点

“可变”关键字被严重误解

也就是说,尽管我所掌握的信息很少,我可能会用上面的方法来做,但我不推荐这样做。几乎可以肯定的是,有一种更好的方法,从更大的角度来看你的问题,这是显而易见的

另一个相遇了
std::vector<double> results = do_calculation(data);
void X::foo(  ) const {
      X & self = const_cast<X &>(*this);
      self.bar( ); //"bar" non-const function
}