13

std::unique_ptr::operator-> has the signature

pointer operator->() const noexcept;

So operator-> is const but returns a mutable pointer. This allows for code like:

void myConstMemberFunction() const
{
    myUniquePtrMember->nonConstFunction();
}

Why does the standard allow this, and what is the best way to prevent usage as presented above?

6
  • I expected it's because the operator . cannot be overloaded. Commented Dec 17, 2015 at 12:01
  • 3
    In C++ const is shallow. An int* const also allows you to modify the pointed to object. Commented Dec 17, 2015 at 12:03
  • 5
    The same code would be allowed if the pointer were not smart. The constness applies to the pointer, not to the pointee. Commented Dec 17, 2015 at 12:03
  • 2
    We have std::experimental::propagate_const if you want to propagate it. Commented Dec 17, 2015 at 12:06
  • 2
    Common misconception about const. Commented Dec 17, 2015 at 12:11

2 Answers 2

19

Think about it like a normal pointer:

int * const i;

is a const pointer to a non-const int. You can change the int, but not the pointer.

int const * i;

is a non-const pointer to a const int. You can change the pointer but not the int.


Now, for unique_ptr, it's a question of whether the const goes inside or outside the <>. So:

std::unique_ptr<int> const u;

is like the first one. You can change the int, but not the pointer.

What you want is:

std::unique_ptr<int const> u;

You can change the pointer, but not the int. Or perhaps even:

std::unique_ptr<int const> const u;

Here you can't change the pointer or the int.


Notice how I always place the const on the right? This is a little uncommon, but is necessary when dealing with pointers. The const always applies to the thing immediately to its left, be that the * (pointer is const), or the int. See http://kuhllib.com/2012/01/17/continental-const-placement/ .

Writing const int, might lead you to thinking int const * is a const-pointer to a non-const int, which is wrong.

Sign up to request clarification or add additional context in comments.

Comments

7

This replicates the semantics of traditional pointers. A const pointer is a pointer that cannot be mutated. However, the object it points to can.

struct bar {
  void do_bar() {}
};

struct foo {
  void do_foo() const { b->do_bar(); } // OK
  bar* const b;
};

To avoid mutating the pointee, you need the unique_ptr equivalent of const pointer to const, or

const std::unique_ptr<const bar> b;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.