如何判断函数是否已被用于修改信息?

时间:2017-04-11 11:49:13

标签: c++

我想做这样的事情:

class bar{
public:
    bool edit;
    int foo[];


    //If the intention is to change some value in foo:
    float & operator [] (int i){
      edit = true;
      return foo[i];
    }

    //But if I just want to read
    float & operator [] (int i){
        return foo[i];
    }
}

如果可以的话,我想要正确的方法。

简单的解决方案是存储两个向量,旧的和新的,并每次检查它们。但我想要一个有效的解决方案,而无需手动更改"编辑"每次我改变一些价值。

也许有r值和l值?

编辑: 例如,如果我将检查" foo"的总和,则存储该值,这样我每次想要知道总和时都不必检查foo,只有当foo被修改时。

7 个答案:

答案 0 :(得分:1)

C ++中的函数可以标记为const,表示它不应该更改信息:

class bar{
public:
    bool edit;
    int foo[];


    //If the intention is to change some value in foo:
    float & operator [] (int i){
      edit = true;
      return foo[i];
    }

    //But if I just want to read
    float operator [] (int i) const {
        return foo[i];
    }
}

另请注意,const函数的返回类型不同 - 返回float而不是float&引用。简单地将函数标记为const实际上并不会阻止它更改类中的信息。相反,此函数用于const副本或类本身的引用。

答案 1 :(得分:1)

一般情况下,如你所知,你不能做你想做的事 - 因为C ++不允许你重写引用是否会被修改。我的建议是:

class bar{
public:
    bool edit;
    int foo[];


    // If I just want to read - use index operator.
    float operator [] (int i) const {
        return foo[i];
    }

    //If the intention is to change some value in foo:
    float & get_ref(int i){
      edit = true;
      return foo[i];
    }
}

换句话说,允许bar_obj[i]获取只读值,但强制使用get_ref来获取可修改的引用。这仍然不能阻止某人写作:

std::cout << bar_obj.get_ref(12);

当返回的值不是实际修改时 - 所以不要这样做!

请注意,如果您的真实用例不是浮点数,operator[]可能会返回const T&

答案 2 :(得分:1)

您可以创建一个假装为float的代理对象,但如果值已更改,则还具有日志记录的附加语义:

#include <cassert>

class bar {
    struct Proxy {
        Proxy(float &f, bool &edit)
            : f{f}
            , edit{edit} {}
        template <class T>
        float &operator=(const T &t) {
            edit = true;
            f = t;
            return f;
        }

        template <class T>
        float &operator+=(const T &t) {
            edit = true;
            f += t;
            return f;
        }

        template <class T>
        auto operator+(const T &t) const {
            return f + t;
        }

        operator float (){
            return f;
        }

        //TODO: add all other relevant operators

        private:
        float &f;
        bool &edit;
    };

    public:
    bool edit{false};
    float foo[42]{};

    //If the intention is to change some value in foo:
    Proxy operator[](int i) {
        return {foo[i], edit};
    }

    //But if I just want to read
    float operator[](int i) const {
        return foo[i];
    }
};

int main() {
    bar b;
    float f = b[0];
    assert(b.edit == false);
    b[0] += f;
    assert(b.edit == true);
}

存在一些问题,例如实现浮点运算符所需的所有代码以及一些隐式转换被禁用,因为我们添加了用户定义的转换,并且添加0将设置edit标志。
此外,我必须更多地考虑如何定义运算符,而不是我为示例在Proxy + Proxy或与其他类型的交互等边缘情况下展示正确的行为。

答案 3 :(得分:0)

无法保证在通过引用获取时实际设置值。我会明确地创建一个getset函数来编辑变量的状态:

class bar{
public:
    bool edit;
    int foo[];

    float get(int i) { return foo[i]; }
    void set(int i, float v) {
        edit = true;
        foo[i] = v;
    }
}

这可以保证所有写入都会被edit变量反映出来,您无法使用当前方法(或提供的其他参考建议)来确保这一点。

答案 4 :(得分:0)

你可以在const-ness上重载operator []std:: containers这样做。

N.B。您可能不希望将非const引用返回到死值,因为使用该值是未定义的行为。

class bar{
public:
    bool edit;
    vector<float> foo; 

    // Mutable float available only to mutable bar's
    float & operator [] (int i){
      edit = true;
      return foo[i];
    }

    // Has to be const float &, as const bar propogates const-ness to it's members
    const float & operator [] (int i) const{
        return foo[i];
    }
}

答案 5 :(得分:0)

您可以使用静态成员作为伪通知程序来跟踪功能访问。当然,您需要知道必须跟踪哪个功能才能实现这一目标。

所以

class bar{
public:
    static int mod_count; //pseudo_notifier
    int foo[];


    //If the intention is to change some value in foo:
    float & operator [] (int i){
      mod_count++;
      return foo[i];
    }

    //But if I just want to read
    float & operator [] (int i){
        return foo[i];
    }

    int getcount()
    {
       return mod_count;
    }

};
bar::mod_count = 0;

int main()
{
  int count = bar::getcount();
  bar mybobj;
  /*
   do whatever operations you plan to do
   myobj[someidx] = 29;

 */
  if(bar::getcount() > count)
   //I know my function has modified the object state  

}

答案 6 :(得分:0)

我会使用显式的getter和setter方法(并使数据保密),而不是重载[]运算符:

class bar
{
    private:
        bool edit;
        int foo[];

    public:
        float get_val(int i) const { return foo[i]; }
        void set_val(int i, float v)
        {
            // Only if new value is different from current value
            if (foo[i] != v)
            {
                edit = true;
                foo[i] = v;
            }
        }

这样就可以确保捕获所有更改,并且没有真正改变任何内容的set操作没有误报(例如将foo[n]设置为已包含的相同值) 。通过将您的数据成员设为私有,您可以阻止任何人编写更改foo但未edit设置的代码。