C++如何断言向量中的所有std::shared_ptr都指向某个对象

7

当我有一个接收(智能)指针并应该引用某些东西的函数时,我总是按照以下方式开始:

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

现在我正在寻找一个类似的断言条件,用于指向(智能)指针的向量(或其他容器)。我能想到的最好方法是:

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; }));
    // ...
}

我想知道是否可以改进这个代码,是否可以避免使用lambda表达式?(我试过使用shared_ptr的get()方法,但是模板推导失败了)或者有其他办法来断言整个容器吗?


2
你不改变函数语法接受 Foo& 作为参数的原因是什么?毕竟,这会_保证_存在一个对象而且无需使用 assert。同样的,向量中也可能包含 std::reference_wrapper<Foo> - paddy
5
assert(!std::count(v.begin(), v.end(), nullptr)); - Piotr Skotnicki
1
@PiotrSkotnicki 遍历所有元素,但当找到第一个不满足条件的元素时,我们可以跳出循环。 - juanchopanza
3
如果存在不满足条件的元素,程序会由于断言失败而终止,在其他情况下会访问所有元素。那么是否真的需要进行最后一次检查以提高运行速度呢? - VLL
3个回答

11

另一种方法:

assert(std::find(pFoos.begin(), pFoos.end(), nullptr) == pFoos.end());

9

另一种只使用标准功能表达它的略微复杂的方法:

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

从C++14开始,您可以使用std::logical_not的通用特化:

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

此解决方案仅适用于 C++14,不适用于 C++11。 - Sandro

1
你可以使用自己实现的实用谓词:
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{});
    // ...
}

并/或者您自己的“范围断言”:

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; });
    // ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接