C++ smart pointer const correctness

user231536 picture user231536 · Jan 17, 2010 · Viewed 32.2k times · Source

I have a few containers in a class, for example, vector or map which contain shared_ptr's to objects living on the heap.

For example

template <typename T>
class MyExample
{
public:

private:
    vector<shared_ptr<T> > vec_;
    map<shared_ptr<T>, int> map_;
};

I want to have a public interface of this class that sometimes returns shared_ptrs to const objects (via shared_ptr<const T>) and sometimes shared_ptr<T> where I allow the caller to mutate the objects.

I want logical const correctness, so if I mark a method as const, it cannot change the objects on the heap.

Questions:

1) I am confused by the interchangeability of shared_ptr<const T> and shared_ptr<T>. When someone passes a shared_ptr<const T> into the class, do I:

  • Store it as a shared_ptr<T> or shared_ptr<const T> inside the container?
  • OR
  • Do I change the map, vector types (e.g. insert_element(shared_ptr<const T> obj)?

2) Is it better to instantiate classes as follows: MyExample<const int>? That seems unduly restrictive, because I can never return a shared_ptr<int>?

Answer

Terry Mahaffey picture Terry Mahaffey · Jan 17, 2010

shared_ptr<T> and shared_ptr<const T> are not interchangable. It goes one way - shared_ptr<T> is convertable to shared_ptr<const T> but not the reverse.

Observe:

// f.cpp

#include <memory>

int main()
{
    using namespace std;

    shared_ptr<int> pint(new int(4)); // normal shared_ptr
    shared_ptr<const int> pcint = pint; // shared_ptr<const T> from shared_ptr<T>
    shared_ptr<int> pint2 = pcint; // error! comment out to compile
}

compile via

cl /EHsc f.cpp

You can also overload a function based on a constness. You can combine to do these two facts to do what you want.

As for your second question, MyExample<int> probably makes more sense than MyExample<const int>.