Lzon.ca. A personal blog, by a programmer and IT expert.

3 min read Original article ↗

Here’s an idea I had for a useful C++ class that adds a little syntactic sugar to null pointer checking.


I’ve come up with an interesting little utility class that I use to make null pointer checking a little nicer to write.

I’ve called it maybe_ptr. It’s a template class that holds a null-able pointer value. The trick it performs is to provide null-safe access to the referenced value through the range-based for syntax. Here’s what that looks like in practice.

static int g_counter=0;

maybe_ptr<int> getCounter(bool can_count)
{
    if (can_count)
        return { &g_counter };
    return { };
}

int main()
{
    for (auto&& counter : getCounter(true))
        counter++; // this statement gets executed

    for (auto&& counter: getCounter(false))
        counter++; // this statement does not

    cout << g_counter << endl; // prints 1
    return 0;
}

This is certainly a little strange, and definitely a hack on the syntax of the for loop. But I think it does a good job expressing the intent in a really concise and readable way.

In this example I want to increment the global counter, but it isn’t always possible to do so because of the can_count parameter. My use of the maybe_ptr ensures that the loop only emits counter once, and only if the underlying pointer isn’t null.

Here’s an implementation of the class.

template<typename T> class maybe_iterator
{
    T* ptr=nullptr;

public:
    using iterator_category = std::random_access_iterator_tag;
    using value_type        = T;
    using difference_type   = std::ptrdiff_t;
    using pointer           = T*;
    using reference         = T&;

    constexpr maybe_iterator(T* p = nullptr) : ptr(p) {}

    constexpr reference operator*() const { return *ptr; }
    constexpr pointer operator->() const { return ptr; }

    constexpr maybe_iterator& operator++() { ptr = nullptr; return *this; }
    constexpr maybe_iterator operator++(int) { auto tmp = *this; ++(*this); return tmp; }

    constexpr bool operator==(maybe_iterator const& other) const { return ptr == other.ptr; }
    constexpr bool operator!=(maybe_iterator const& other) const { return ptr != other.ptr; }
};

template <typename T> struct maybe_ptr
{
    T* ptr=nullptr;

    auto begin() { return maybe_iterator<T>(ptr); }
    auto end() { return maybe_iterator<T>(nullptr); }
};

The class has the requisite begin() end() methods which allow it to interact with the range-based for loop. The additional iterator class does the null check. It says “if the pointer is not null, dereference and emit. If it is null, iteration has ended”

Another perspective is that this is an iterable object that has precisely zero or one element, dependent on the null-ness of the underlying pointer.

This isn’t my original idea, not entirely. It’s a riff on the new proposal for std::optional in C++26, which has a very similar design and rationale. My class is specifically adapted for handling null-able pointers in the same elegant way.


Did you find this useful? Do you have any interesting C++ tricks of your own? If so, let me know!

Send a message to mail@lzon.ca, or DM me on one of my social accounts on the homepage.