Table of Contents

The C++ Standard moves at a fast pace. Probably, not all developers caught up with C++11/14 yet and recently we got C++17. Now it’ time to prepare C++20!
A few weeks ago The C++ Committee had an official ISO meeting in Jacksonville, FL (12-17 March 2018) where they worked hard on the new specification.

Besides many significant things that were discussed at the meeting like modules, concepts, ranges, The C++ Committee accepted one hugely anticipated feature: deprecation of raw pointers!

This post is April Fool’s joke :)
But maybe it’s not a totally wrong idea to abandon raw pointers? :)

Intro  

If you’d like to read about all of the changes that the Committee did for C++20 you can check various trip reports that appeared recently. For example:

Honestly, I rolled my eyes when I saw the proposal of removing raw pointers! Such task looks so complicated! How do they plan to implement that? And what about backward compatibility that is one of the primary goals of new language releases?

But then I understood how excellent that move really is.

Just to be clear about the spec:

The plan is to deprecate raw pointers in C++20. So you’ll get a warning from a conformant compiler. Later in C++23 or C++26, raw pointers will be removed from the language. See more details under this link.

Reasoning  

How many times were you tracing some bug, probably for long hours, before noticing the main reason was just having an invalid pointer?

Of course, knowing that your pointer is invalid is not as easy as it may sound. Even if you delete ptr; and set it to nullptr you’re not safe. A pointer only represents a memory address, so if you assign it to nullptr, there’s no automatic propagation of that change to all the owners or observers of this pointer.

The pointer-specific issues (memory issues, pointer indirection, unsafe calls or memory access, to name a few) are probably one of the main the most frequent reasons why our language C++ is perceived as hard to use.

Have a look at Rust. They make a lot of efforts to make the language reliable. It’s still a systems programming language, compiled to machine code. But Rust offers many safety checks. You can use raw pointers but in only a few places. And most of the time the language gives you better alternatives.

Ok, ok… but raw pointers are useful in a lot of cases! So let’s have a look what the Committee proposes as alternatives:

Alternatives to raw pointers  

Here are the main examples where raw pointers are handy, and what can we use from modern C++ to exchange them.

Avoiding copying / aliasing  

One of an obvious reason to use pointers is to hold an address of some object so that you can manipulate it without the need to copy. Especially handy for passing to functions:

void Process(GameObject* pObj) {
    pObj->Generate();
}

Unfortunately, such code is a common “unsafe” place. For example, you often need to check if such input pointer is not null. Otherwise dereferencing an invalid pointer might generate an unexpected crash.

We have a few alternatives here:

  • Pass a value - if your object support move semantics then the copy might not cost much
  • Pass a smart pointer
  • Pass a reference
  • For copyable and assignable references you can use std::reference_wrapper.

For now, you can also consider using gsl::not_null which I described in this post: How not_null can improve your code?.

Polymorphism  

References and smart pointers will handle polymorphism. So no worries here.

Dynamic memory allocation  

In modern C++ you should avoid using explicit new. You have many tools to simplify that, like std::make_shared, std::make_unique . It’s another case where using a raw pointer is not needed.

std::shared_ptr<int[]> ptrArray(new int[N]); // since C++17

Observing other objects  

Using raw pointers for observing other objects is probably the main issue that caused the change in the standard. With raw pointers, you are not sure if the pointer is still valid. Therefore there are many cases where you might encounter an access violation error.

By using smart pointers, you can safely avoid many of such issues. For example, with weak_ptr you can check if the pointer is still alive or not.

void observe(std::weak_ptr<GameObject> pObj) 
{
    if (auto observePtr = pObj.lock()) {
        // object is valid
    } else {
        // invalid
    }
}

Nullable objects  

Pointers are also used to transfer the information about the results of some operations:

File* Open() { ... }

auto f = Open();
if (f)
{
}

Here we have two problems: the same variable is used to store the objects (the file) and also to convey the message if that object is valid or not. With C++17 we have std::optional that is perfectly suited for that role. It’s far more expressive and safer.

Performance  

Safety is not cheap, and sometimes we must give a bit of performance to have more checks and validations. However, in C++, a lot of pointers alternatives offer no runtime cost. For example, unique_ptr is safe, and decays to almost nothing, to a raw pointer under the hood. Hence, any memory access made by using this pointer is as cheap as a usage of raw pointer.

Accessing a shared_ptr is also as fast as a raw pointer, but when copying, shared_ptr needs to manage the control block which involves atomic operations.

Sorry for a little interruption in the flow :)
I’ve prepared a little bonus if you’re interested in smart pointers - a reference card, check it out here:

Download a free copy of my C++ Smart Pointers Ref Card!

Wrap up  

From my perspective, the step of removing pointers will give us an entirely new language! C++ will be safer and more straightforward to learn. What’s more, we don’t lose any performance as we have alternatives that are also as close to the metal as raw pointers.

The devil lies in details, and the Committee needs to do a lot of work to make the final specification. Maybe we’ll get some new mechanism for dealing with pointers: like deferred_ptr or even some garbage collection mechanisms?

There’s an excellent presentation from Herb Sutter about “Leak Freedom”, and you can watch it here:

This post is April Fool’s joke :) But maybe it’s not a totally wrong idea to abandon raw pointers? :)

What’s your view on that?
Can you live without raw pointers?