lundi 25 avril 2016

Breaking encapsulation by returning non-const references to members

Say I have a class Foo with a vector_ data member like so:

class Foo {
public:
    const std::vector<int> & vector() const {
        return vector_;
    }
    void vector(const std::vector<int> &vector) {
        vector_ = vector;
        // Other operations which need to be done after the 
        // vector_ member has changed
    }
private:
    // Some large vector
    std::vector<int> vector_;
};

I often face situations like these

void someOperation(std::vector<int> &v) {
    // Operate on v, but almost always let v's size constant
}

int main() {
    // Create Foo object
    Foo foo;
    // Long loop
    for (auto k = 0; k < 100; k++) {
        auto v = foo.vector();
        someOperation(v);
        foo.vector(v);
    }
}

where I can't pass foo's (possibly large) vector_ member directly to someOperation due to the (const-correct) implementation of the vector method to access the member. Although someOperation almost always lets its argument's size unchanged, I need to copy the vector first, then pass it to someOperation and then to foo's setter. Clearly, I can avoid this extra copy if I remove the const-ness of the Foo's class getter and call an afterChange method after the member has been changed by someOperation - but this breaks encapsulation:

class Foo {
public:
    std::vector<int> & vector() { // Note we now return by non-const reference
        return vector_;
    }
    void afterChange() {
        // Other operations which need to be done after the 
        // vector_ member has changed
    }
private:
    std::vector<int> vector_;
};

Are there any other alternatives? Or is this one of the situations where breaking encapsulation is legitimate?

Aucun commentaire:

Enregistrer un commentaire