Search code examples
c++c++11constantsshared-ptr

How to write a getter for a container of shared_ptrs which does not allow modification of data


Let's say I have a private variable which is a vector of shared_ptrs to non-const objects.

Is it possible to write a getter method which only allows read access to the data pointed to by the shared pointers?

I want to be able to use range-based loops for elegance, so I want to avoid writing const_iterators.

My understanding is that const shared_ptr<T> makes the pointer itself const, not T. I tried to compile shared_ptr<const T>, but it doesn't compile if T itself is not declared const in the class.

In other words, how could I write something like:

#include <iostream>
#include <vector>
#include <memory>

using std::vector;
using std::shared_ptr;
using std::make_shared;
using std::cout;
using std::endl;

class MyClass{

public:
    MyClass(int element1, int element2)
    {
        myVector_.push_back(std::make_shared<int>(element1));
        myVector_.push_back(std::make_shared<int>(element2));
    }

    // I want something like this, but doesn't compile
//  const vector<shared_ptr<const int>> readMyVector() const {return myVector_;}

    const vector<shared_ptr<int>> readMyVector() const {return myVector_;}

private:

    // Should NOT be <const int>, the class should be able to modify its elements
    vector<shared_ptr<int>> myVector_;
};

int main(){
    auto testobject = MyClass(1,2);
    for (auto my_protected_data : testobject.readMyVector()){
        cout<<(*my_protected_data)<<endl;
        (*my_protected_data) = 25;
        cout<<(*my_protected_data)<<endl; // Should not happen
    }
    return 0;
}

Solution

  • The correct type to return is std::vector<std::shared_ptr<const int>>, but you'll have to make that vector by hand. std::shared_ptr<T> is convertible to std::shared_ptr<const T>, but the problem is that std::vector<T> isn't implicitly convertible to std::vector<U> simply because T is convertible to U.

    The easiest way is to construct a vector from your internal vector's begin and end iterators.

    vector<shared_ptr<const int>> readMyVector() const 
    {
        return{ myVector_.begin(), myVector_.end() };
    }
    

    Note that adding const to the return type of a function that returns by value is rarely useful.

    You should also ask yourself rather it's worth it to copy all of those std::shared_ptr. You may want to consider simply returning a vector of int.