首页 > 解决方案 > 在向量中重载 push_back() 以允许不重复的元素

问题描述

我们可以重载push_back()方法std::vector以允许不重复的元素吗?我知道std::set并且std::unordered_set应该避免重复元素,但是std::set对元素进行排序并std::unordered_set以不特定的顺序存储元素。我需要按照插入的顺序检索元素,同时确保不插入重复的元素。

编辑:这个问题在这里可能有重复。这种重复的最佳解决方案建议具有辅助数据结构和另一种自定义方法“添加”。这对我来说看起来不太好,因为(我将把它放在单独的文档中)插入数据的用户std::vector很少参考任何自定义函数的文档。如果没有有效的方法,这可能是最后的手段。

标签: c++vectorsetpush-backunordered-set

解决方案


许多人反对它,但似乎有某种都市传说正在流传,这样做会导致宇宙经历真空衰变,而我们所知道的现实将会溶解。

您可以公开继承自std::vector. 但是你必须考虑你能用它做什么。

如果您继承自vector,强烈建议您不要向其中添加任何数据成员。这可能会导致对象切片(谷歌“c++ 对象切片”。)您还需要记住vector不使用虚函数。这意味着您不能覆盖成员函数。您只能隐藏它们,因此不能保证它始终是您的push_back()函数被调用。例如,如果您将类的对象传递给引用 a 的对象,则会调用原始对象vector

所以最后,你需要添加一个push_back_unique()函数。但这反过来意味着可以通过一个简单的免费函数来提供服务。vector所以不需要继承。这当然意味着永远不能保证向量中的元素是唯一的。其他代码可能会在push_back()某处使用。

如果您想添加不强加或解除任何限制的全新便利功能,继承vector是有意义的vector。如果您想要看起来像vector但实际上不是的东西(因为它具有不同的行为和/或限制),您应该实现自己的类型,vector通过从它私有继承或将其作为容器功能委托给它私有数据成员,然后vector通过公共包装函数复制 API。

但这实施起来非常繁琐。通常,您并不需要 vector 的所有 API。所以我想说只写一个围绕向量的更小的类,它只提供你需要的功能。而且该功能听起来几乎是只读的,因为允许对元素的写访问允许将元素设置为与另一个元素相同的值,从而破坏了容器的唯一性。因此,您可以执行以下操作:

template<typename T>
class UniqueVector
{
public:
    void push_back(T&& elem)
    {
        if (std::find(vec_.begin(), vec_.end(), elem) == vec_.end()) {
            vec_.push_back(std::forward(elem));
        }
    }

    const T& operator[](size_t index) const
    {
        return vec_[index];
    }

    auto begin() const
    {
        return vec_.cbegin();
    }

    auto end() const
    {
        return vec_.cend();
    }

private:
    std::vector<T> vec_;
};

如果您仍然希望允许对单个元素进行写访问,那么您可以提供非常量函数来检查传递的值是否已经在向量中。喜欢:

void assign_if_unique(size_t index, T&& value)
{
    if (std::find(vec_.begin(), vec_.end(), value) == vec_.end()) {
        vec_[index] = std::forward(value);
    }
}

这是一个最小的例子。您显然应该添加您真正想要的功能。像size(),empty()和其他任何你需要的东西。


推荐阅读