MK.
MK.

Reputation: 34597

C++ what is the idiomatic way to avoid pointers?

I have a method which takes const ref to a set. I want to call it and m.b. pass a set to it. If I have it. So first I see if I have a set:

const auto& it = mapOfSets.find("token");
if (it != std::end(mapOfSets)) {
  myFunction(it.second);
} else {
  MySetType emptySet;
  myFunction(emptySet);
}

What is an idiomatic way of doing this? I don't like the above because call to myFunction is repeated twice and there is a few other arguments, so there is some unnecessary code duplication.

The C programmer in me just wants to change the function to accept a pointer and pass nullptr if set is not found, but i feel that C++ is all about avoiding pointers now?..

Upvotes: 2

Views: 541

Answers (3)

JiaHao Xu
JiaHao Xu

Reputation: 2748

Maybe a handwritten optional_reference that can reference nullptr but will throw when dereferencing it and has no additional bool

#include <stdexcept>
#include <memory>

class null_access_exception: public std::logic_error
{
    using base = std::logic_error;
public:
    null_access_exception():
        base("Try to dereference null optional_reference!")
    {}
};

template <class Ptr_t>
class optional_reference
{
    using self = optional_reference;
    using reference = decltype(*std::declval<Ptr_t>());
    Ptr_t ptr = nullptr;

public:
    optional_reference() = default;
    optional_reference(const self&) = default;

    self& operator = (const self&) = delete;

    template <class U>
    constexpr optional_reference(U &&obj) noexcept: 
        ptr(std::addressof(obj))
    {}

    constexpr explicit operator bool() const noexcept
    { return has_value(); }

    constexpr bool has_value() const noexcept
    { return ptr != nullptr; }

    constexpr auto& value() const
    {
        if (!has_value())
            throw null_access_exception();

        return *ptr;
    }

    template <class U>
    constexpr auto& value_or(U &&obj) const noexcept
    {
        if (has_value())
            return *ptr;
        else
            return reference(std::forward<U>(obj));
    }
};

and then

  1. Change myfunction so that it accept optional_reference and then check it.

  2. Wrap it like below.

    constexpr const static auto null_set(); void Myfunction(optional_wrapper ref) { myfunction(ref.value_or(null_set)); }

Upvotes: 0

Chris Drew
Chris Drew

Reputation: 15334

If you write a helper function to find a set in the map then you can return a reference to a special empty set in the case that you did not find anything:

const MySetType& find(const MyMapType& mapOfSets, const std::string& key) {
    auto it = mapOfSets.find(key);
    if (it != std::end(mapOfSets)) {
        return it->second;
    }
    static const MySetType emptySet;
    return emptySet;
}

Then your calling code is simply:

myFunction(find(mapOfSets, "token"));

Upvotes: 1

Rakete1111
Rakete1111

Reputation: 49028

You can use the conditional operator:

myFunction(it != mapOfSets.end() ? it->second : MySetType{});

I don't think there is an idiomatic way though.

Upvotes: 3

Related Questions