7

When I have a function receiving a (smart) pointer that is supposed to refer something, I always start as follows:

class Foo;
void doSomething(const std::shared_ptr<Foo>& pFoo)
{
    assert(pFoo);
    // ...
}

Now I am looking for a similar assert condition for a vector (or other container) of (smart) pointers. The best I could come up with is:

void doSomething(const std::vector<std::shared_ptr<Foo> >& pFoos)
{
    assert(std::all_of(pFoos.begin(), pFoos.end(), [](const std::shared_ptr<Foo>& pFoo) { return pFoo; }));
    // ...
}

I wonder whether this could be improved.. can the lambda be avoided? (I tried to use the get() method of shared_ptr but template deduction fails then) Or is there another way to assert for a whole container?

Cœur
  • 37,241
  • 25
  • 195
  • 267
mr_T
  • 2,571
  • 3
  • 22
  • 39
  • 2
    Is there any reason why you wouldn't change your function's syntax to receive a `Foo&` instead? After all, that _guarantees_ there is an object and no assert is required. Similarly with the vector, which could contain `std::reference_wrapper`. – paddy Dec 08 '16 at 10:55
  • 5
    `assert(!std::count(v.begin(), v.end(), nullptr));` – Piotr Skotnicki Dec 08 '16 at 10:58
  • 1
    @PiotrSkotnicki That visits all the elements, whereas we can break out when the first one that doesn't satisfy a condition is found. – juanchopanza Dec 08 '16 at 11:19
  • 3
    @juanchopanza The program terminates due to assertion failure, if there is an element that does not satisfy conditions, and visits all elements in every other case. Is there really a need to make that one final check to run faster? – VLL Dec 08 '16 at 11:56

3 Answers3

11

one more way to do it:

assert(std::find(pFoos.begin(), pFoos.end(), nullptr) == pFoos.end());
Sandro
  • 2,707
  • 2
  • 20
  • 30
9

Another slightly convoluted way to express it with standard functionality only:

assert(std::none_of(pFoos.begin(), pFoos.end(), std::logical_not<std::shared_ptr<Foo>>{}));

From C++14 onwards, you can use the generic specialization of std::logical_not:

assert(std::none_of(pFoos.begin(), pFoos.end(), std::logical_not<>{}));
Quentin
  • 62,093
  • 7
  • 131
  • 191
1

You could use implement your own utility predicate:

struct is_nullptr
{
    template <typename T>
    bool operator()(T&& x) const noexcept { return x == nullptr; }
};

void doSomething(const std::vector<std::shared_ptr<Foo> >& pFoos)
{
    assert(!std::any_of(pFoos.begin(), pFoos.end(), is_nullptr{});
    // ...
}

And/or your own "range assertion":

template <typename TContainer, typename TPredicate>
void range_assert(TContainer&& container, TPredicate&& p)
{
    for(auto&& x : container)
    {
        assert(p(x));
    }
}

void doSomething(const std::vector<std::shared_ptr<Foo> >& pFoos)
{
    range_assert(pFoos, [](const std::shared_ptr<Foo>& x) { return x; });
    // ...
}
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416