Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a unique_ptr whose pointer and data is const

Tags:

c++

unique-ptr

The first time I tried to write a range based for loop to iterate over unique_ptrs I wrote:

std::vector<std::unique_ptr<Foo>> vec;
// Initialize vec

for (auto v : vec) // error
{}

I then realized this is trying to create a copy of each element which doesn't make sense with a unique_ptr. So then I wrote it as a reference:

for (auto& v : vec)
{}

Adding a const in front of it keeps me from changing the pointer.

for (const auto& v : vec)
{
   v = nullptr; // error (good!)
}

How can I write it, so that the data pointed to cannot be changed? For example, the following code should not compile.

for (??? v : vec)
{
   v->func();
}

class Foo
{
public:
   void func();

private:
   bool mBar;
}

Foo::func()
{
   mbar = true; // Should cause error
}
like image 937
user870130 Avatar asked Apr 07 '14 13:04

user870130


2 Answers

To prevent the data from being modified, include const in the template parameter for your pointer:

std::vector<std::unique_ptr<const Foo>> vec;

I think you'll have problems making the pointer itself const though. The reason is that the vector has to be able to copy the pointer object around internally (e.g. when the container is resized). With a unique_ptr, that means ownership has to be transferred between instances, meaning it has to be mutable (not const).

To make the pointer itself const, I think you've got two main choices: use a vector of const shared_ptr<>, or an array (i.e. fixed size) of const unique_ptr<>.

like image 160
Peter Bloomfield Avatar answered Nov 14 '22 20:11

Peter Bloomfield


For that, your unique_pointer must be instantiated for a const-qualified type, like this:

std::vector<std::unique_ptr<const Foo>> vec;

But maybe it is enough to use the iterator to initialise a constant reference at the start of the loop, the compiler should optimise it away:

for (const auto& v_iter : vec) {
    const auto& x = *v_iter;
    do_things(...);
}

Everything else is hackery.

What probably would work is reinterpreting your vector<unique_pointer<Foo>> as a vector<unique_pointer<const Foo>>, but it might result in hilarious undefined behavior if either vector or unique_pointer has a specialisation. Do not try, it is not worth that.

like image 45
Deduplicator Avatar answered Nov 14 '22 22:11

Deduplicator