Search code examples
c++effective-c++dangling-pointer

How to avoid returning handles to object internals - Item 28 Effective C++


Item 28 of Effective C++ says avoid returning "handles" to object internals. This question shows how to design your code to do exactly that by thinking about encapsulation in order to avoid accidentally exposing the internals of your class.

My example involves a data array and since memory is an issue I'd like to avoid using std::vector (and the Boost library).

Using an array here's a very simplified version of my code:

class Foo {
public:
    Foo(int size) : data_(new int[size]) {
        // Populate with data just for the example
        for(int i = 0; i < size; i++) {
            data_[i] = i;
        }
    }

    // I know that this isn't good practice
    int* const get_data() const {
        return data_;
    }

    ~Foo() {
        delete[] data_;
    }

private:
    int* data_;
};

int main(void) {
    Foo* foo = new Foo(10);
    int* const data = foo->get_data();
    delete foo;
    // data now dangles which is bad!
    return 0;
}

I understand that using const with get_data() doesn't make it safe. If I was using a vector I could copy it like the example question above, but since I'd like to avoid this I was wondering how best to design my class to avoid this potentially dangerous situation?


Solution

  • Programming and software design is a constant "choice of one thing over another". If you REALLY can't afford using std::vector, and you need to expose data to the client-code using your class, then so be it. Document why it is so, and make sure that it's reviewed over time - it may be that when your new model of hardware that has 8MB of RAM instead of 2MB will be able to use the extra 4 bytes that a vector takes over your plain pointer.

    Or write an accessor function:

    int& Foo::operator[](int pos)
    {
       // Add checks here to ensure `pos` is in range?
       return data[pos]; 
    }
    

    Now you don't have to return the pointer at all...