初始化后具有固定容量的C ++向量

时间:2018-12-26 13:18:47

标签: c++ vector

我需要一个具有以下要求的C ++容器:

  • 该容器可以将不可复制和不可移动的对象存储在连续内存中。对于std::vector,对象必须是可复制的或可移动的。
  • 容器的capacity在运行时的构造过程中是已知的,并且一直固定到破坏为止。在构造过程中分配了所有需要的内存空间。对于boost::static_vector,容量是在编译时知道的。
  • 当容器中有emplace_back个元素时,容器的大小会随着时间增加,但绝不能超过capacity
  • 由于该对象不可复制或不可移动,因此不允许重新分配。

似乎STL和BOOST都没有我需要的容器类型。我也在这一方面进行了广泛搜索,但没有找到答案。所以我实现了一个。

#include <memory>

template<class T>
class FixedCapacityVector {
private:
    using StorageType = std::aligned_storage_t<sizeof(T), alignof(T)>;
    static_assert(sizeof(StorageType) == sizeof(T));
public:
    FixedCapacityVector(FixedCapacityVector const&) = delete;
    FixedCapacityVector& operator=(FixedCapacityVector const&) = delete;
    FixedCapacityVector(size_t capacity = 0):
        capacity_{ capacity },
        data_{ std::make_unique<StorageType[]>(capacity) }
    { }
    ~FixedCapacityVector()
    {
        for (size_t i = 0; i < size_; i++)
            reinterpret_cast<T&>(data_[i]).~T();
    }
    template<class... Args>
    T& emplace_back(Args&&... args) 
    {
        if (size_ == capacity_)
            throw std::bad_alloc{};
        new (&data_[size_]) T{ std::forward<Args>(args)... };
        return reinterpret_cast<T&>(data_[size_++]);
    }
    T& operator[](size_t i) 
    { return reinterpret_cast<T&>(data_[i]); }
    T const& operator[](size_t i) const 
    { return reinterpret_cast<T const&>(data_[i]); }
    size_t size() const { return size_; }
    size_t capacity() const { return capacity_; }
    T* data() { return reinterpret_cast<T*>(data_.get()); }
    T const* data() const { return reinterpret_cast<T const*>(data_.get()); }
private:
    size_t const capacity_;
    std::unique_ptr<StorageType[]> const data_;
    size_t size_{ 0 };
};

我的问题是:

  • 我为什么要手工这样做?我找不到标准容器。或者,也许我没有看对地方?还是因为我想做的不是常规的?
  • 手写容器是否正确实施?异常安全性,内存安全性等如何?

3 个答案:

答案 0 :(得分:1)

它可能无法完全回答问题,但根据以下文件,看来 fixed_capacity_vector 可能会添加到将来的C ++标准中。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0843r1.html

简介

本文提出了boost :: container :: static_vector [1]的现代化版本。也就是说,具有可编译时间固定容量的动态可调整大小的向量,并且具有连续的嵌入式存储,其中的元素存储在向量对象本身内。

它的API非常类似于std :: vector。它是一个连续的容器,在末尾有O(1)插入和删除元素(未摊销),在其他情况下,最坏情况是O(size())插入和删除。像std :: vector一样,元素在插入时初始化,在删除时销毁。对于琐碎的value_types,向量可在constexpr函数中完全使用。

答案 1 :(得分:0)

  

我为什么要手动这样做?我找不到标准容器。或者,也许我没有看对地方?还是因为我想做的不是常规的?

这不是常规。按照惯例, MoveConstructible 也是 MoveAssignable

  

手写容器是否正确实施?异常安全性,内存安全性等如何?

data有问题。调用者可能会假设他们可以增加该指针以获取其他元素,但这绝对是未定义的。您实际上没有T数组。该标准要求在std::vector中使用实现定义的魔术。

答案 2 :(得分:0)

我知道这是一篇有点老的帖子,并没有提出确切的要求,但是,我们开源了多年来在我公司生产代码中使用的 FixedCapacityVector 的实现,可用于 here。容量应该是一个编译时常量。

它需要 C++11 编译器,但 API 符合 C++17 的 std::vector