可变与懒惰评估

时间:2015-02-17 10:03:36

标签: c++ const lazy-evaluation mutable

最近我在const-correctness上阅读this faq。现在我遇到了以下情况,我不知道该怎么做const或mutable。 假设一个简单的例子:

class Averager {
public:
    Averager() : sum(0),isUptoDate(false),N(0){}
    void add(double x){
        sum+=x;
        N+=1;
        isUptoDate = false;
    }
    double getAverage() const {
        if (!isUptoDate){updateAverage();}
        return average;
    }
private:
    void updateAverage(){
        if(N>0){average = sum / N;}
        else   {average = 0;}
        isUptoDate = true;
    }    
    double sum;
    mutable bool isUptoDate;
    int N;
    double average;
};

在实际情况中,updateAverage()是一项昂贵的计算,因此我希望每次添加值时都不要更新。此外,在添加新值之前,可能会多次调用getAverage(),因此我只想在真正需要时才更新。另一方面,类的用户不应该负责调用updateAverage(),因此我使用该标志来知道是否必须进行更新。

据我了解,getAverage()显然应该是const方法,而isUptoDate可以是可变的(它不是逻辑状态的一部分,而只是私有实现细节)。但是,updateAverage()绝对不是const,我不能在const方法中调用它。

我的做法出了什么问题?

1 个答案:

答案 0 :(得分:3)

我看起来很好,你只需要使你的average也变得可变,因为它会被getAverage懒惰地计算出来。 updateAverage也应为const,因为它将由getAverage调用。由于updateAverage是私有的,因此它自己的存在是一个实现细节。它只被调用一次,您也可以将其内联到getAverage

double getAverage() const {
    if (!isUptoDate){
        if(N>0){average = sum / N;}
        else   {average = 0;}
        isUptoDate = true;
    }
    return average;
}

确实,我真的建议你内联它,因为将它放在头文件中是没有意义的(如果你改变它的签名或它的常量,你必须重新编译所有用户) 。如果它不仅仅是真实案例中的3行,你可以将它作为lambda,如果你使用C ++ 11:

double getAverage() const {
    auto updateAverage=[&]{
        if(N>0){average = sum / N;}
        else   {average = 0;}
        isUptoDate = true;
    };
    if (!isUptoDate){ updateAverage(); }
    return average;
}