恒定大小的矢量

Constant-sized vector

本文关键字:      更新时间:2023-10-16

有人知道定义常量大小向量的方法吗?

例如,而不是定义

std::vector<int>

这将是

std::vector<10, int>

它应该是完全跨平台的。也许是一个开源类?

std::vector 始终可以动态增长,但有两种方法可以分配初始大小:

这将分配初始大小并用零填充元素:

std::vector<int> v(10);
v.size(); //returns 10

这将分配一个初始大小,但不用零填充数组:

std::vector<int> v;
v.reserve(10);
v.size(); //returns 0

无法定义常量大小向量。如果你在编译时知道大小,你可以使用 C++11 的 std::array 聚合。

#include <array>
std::array<int, 10> a;

如果您没有相关的 C++11 支持,则可以使用 TR1 版本:

#include <tr1/array>
std::tr1::array<int, 10> a;

或 boost::array,正如其他答案中所建议的那样。

这是一个

老问题,但如果有人只需要在运行时定义大小的恒定大小索引容器,我喜欢使用unique_ptr

// c++14
auto constantContainer = std::make_unique<YourType []> ( size );
// c++11
std::unique_ptr<YourType[]> constantContainer {new YourType[ size ]};

// Access
constantContainer[ i ]
如果你

想要一个固定的编译时指定大小(ala std::array<T, N>),但你希望能够在0N之间用不同数量的元素填充向量,那么一个不错的选择是eastl::fixed_vector

标准::向量:

std::vector的大小是动态的 - 它将动态分配所需的存储,您无法限制大小并强制实施错误。

但是,您可以reserve特定大小,然后在需要分配新存储之前添加该大小的元素。

vector.size()最初为 0,并随着您添加元素而增加

标准::数组:

std::array的大小是一个编译时常量 - 它将静态分配所需的存储,并且您无法更改大小。

array.size()始终是数组的大小,等于array.max_size()

eastl::fixed_vector:

eastl::fixed_vector的大小可以是静态的,也可以是动态的。

它最初会分配一定数量的元素,然后如果你允许动态增长,如果需要,它会动态分配。

出于您最初要求的目的,您可以禁用增长(通过下面的模板实例化中的bEnableOverflow

fixed_vector.size()最初为 0,并随着您添加元素而增加。

template<typename T, 
         size_t nodeCount, 
         bool bEnableOverflow = true, 
         typename OverflowAllocator = 
                      typename eastl::type_select<bEnableOverflow,
                                                  EASTLAllocatorType, 
                                                  EASTLDummyAllocatorType>::type>
class fixed_vector;

简单的例子:

#include <iostream>
#include <vector>
#include <array>
#include "EASTL/fixed_vector.h"
int main()
{
    std::vector<int> v;
    v.reserve(10);
    std::cout << "size=" << v.size() << " capacity=" << v.capacity() << 'n';
    std::array<int, 10> a;
    std::cout << "size=" << a.size() << " capacity=" << a.max_size() << 'n';
    eastl::fixed_vector<int, 10, false> fv;
    std::cout << "size=" << fv.size() << " capacity=" << fv.capacity() << 'n';
    return 0;
}

输出:

size=0 capacity=10
size=10 capacity=10
size=0 capacity=10

请注意,array 的大小为 10,而 vectorfixed_vector 的大小为 0

使用 std::array c++11

为了获得更好的可读性,您可以制作 typedef:

typedef std::array<int, 10> MyIntArray;

std::vector是一个动态容器,没有限制其增长的机制。分配初始大小:

std::vector<int> v(10);

C++11 有一个更合适的std::array

std::array<int, 10> my_array;

如果您的编译器不支持 C++11,请考虑使用 boost::array

boost::array<int, 10> my_array;

此----> std::vector<10, int>无效并导致错误。但新的C++标准引入了一个新的类别;标准::数组。你可以声明一个这样的数组:

std::array<int, 5> arr; // declares a new array that holds 5 ints
std::array<int, 5> arr2(arr); // arr2 is equal to arr
std::array<int, 5> arr3 = {1, 2, 3, 4, 5}; // arr3 holds 1, 2, 3, 4, 5

std::array具有恒定的大小并支持iterator/const_iterator/reverse_iterator/const_reverse_iterator。您可以在 http://cplusplus.com/reference/stl/array/找到有关此课程的更多信息。

改进来自 Pari
的答案多年来,我一直在数字处理应用程序中使用以下类:

inline void nodeleter(void*) {}
/// Array of T with ownership. Like see std::unique_ptr<T[]> but with size tracking.
/// @tparam T Element type.
template <typename T>
class unique_array : public std::unique_ptr<T[],void (*)(void*)>
{   size_t Size;
private:
    typedef std::unique_ptr<T[],void (*)(void*)> base;
protected:
    unique_array(T* ptr, size_t size, void (*deleter)(void*)) noexcept : base(ptr, deleter), Size(size) {}
    void reset(T* ptr, size_t size) noexcept { base::reset(ptr); Size = size; }
public:
    constexpr unique_array() noexcept : base(nullptr, operator delete[]), Size(0) {}
    explicit unique_array(size_t size) : base(new T[size], operator delete[]), Size(size) {}
    template <size_t N> unique_array(T(&arr)[N]) : base(arr, &nodeleter), Size(N) {}
    unique_array(unique_array<T>&& r) : base(move(r)), Size(r.Size) { r.Size = 0; }
    void reset(size_t size = 0) { base::reset(size ? new T[size] : nullptr); Size = size; }
    void swap(unique_array<T>&& other) noexcept { base::swap(other); std::swap(Size, other.Size); }
    void assign(const unique_array<T>& r) const { assert(Size == r.Size); std::copy(r.begin(), r.end(), begin()); }
    const unique_array<T>& operator =(const unique_array<T>& r) const { assign(r); return *this; }
    size_t size() const noexcept { return Size; }
    T* begin() const noexcept { return base::get(); }
    T* end() const noexcept { return begin() + Size; }
    T& operator[](size_t i) const { assert(i < Size); return base::operator[](i); }
    unique_array<T> slice(size_t start, size_t count) const noexcept
    {   assert(start + count <= Size); return unique_array<T>(begin() + start, count, &nodeleter); }
};
  • 分配是可能的,但这不能改变大小(尽管它很容易实现)。
  • 您可以通过调用 reset 来更改大小,但顾名思义,这会丢弃任何数据。
  • 支持移动语义
  • const实例不会使其内容const。只有存储无法更改。
  • 它还限制了对不属于实例的切片的支持。但他们没有终身管理。你需要自己关心悬空的引用。
  • 缺少一些功能才能完全兼容C++ Container要求,首先是typedefs。到目前为止,我从来不需要它们。
  • 很容易
  • 为数值类型扩展此类型并添加进一步的向量运算。但是没有直接的自动性,因为至少std::is_arithmetic<std::complex<double>>::value是错误的。

我发现std::vector实际上max_size()成员,并且 std 库中有一个自定义点来相应地调整向量行为。所以我只是调整了std::vector,以在max_size()和狭窄的size_type上应用上限.使用 c++11 及更高版本进行编译

    -
  • 错误 -Wextra
    • 海湾合作委员会>= 4.9.0
    • 叮当>= 3.3
  • /
  • W4/WX/外部:尖括号/外部:W3
    • MSVC>= 19.20

大多数代码都是毫无意义的样板代码,如果您不需要支持跨平台编译和/或旧版本的 c++,您可以轻松切断,唯一真正的逻辑是在 Allocator 成员内部。使用与标准兼容的任何分配器和矢量类型,您可以拥有加帽矢量。 using CapedVector = Caped<uint16_t>::Vector<char>; 如果您不需要缩小size_type,您可以删除Vector并使用template <class T> using CapedVector = std::vector<T, Caped<uint16_t>::Allocator<std::allocator<T>>>

#include <algorithm>
#include <limits>
#include <memory>
#include <vector>
#include <type_traits>
#if __cpp_constexpr >= 201603L
// c++17
#define NODISCARD [[nodiscard]]
#else
#define NODISCARD
#endif
#if __cpp_constexpr > 200704L
// c++14
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif
#ifndef __cpp_concepts
template <class Size, Size maxSize = std::numeric_limits<Size>::max(), class = typename std::enable_if<std::is_unsigned<Size>::value>::type>
#elif defined CONSTEXPR
template <class Size, Size maxSize = std::numeric_limits<Size>::max(), class = std::enable_if_t<std::is_unsigned_v<Size>>>
#else
template <class Size, Size maxSize = std::numeric_limits<Size>::max()> requires(std::is_unsigned_v<Size>)
#endif
struct Caped
{
    using size_type = Size;
    template <class A>
    struct Allocator : A
    {
        using value_type = typename std::allocator_traits<A>::value_type;
        using pointer = typename std::allocator_traits<A>::pointer;
        using const_pointer = typename std::allocator_traits<A>::const_pointer;
        using void_pointer = typename std::allocator_traits<A>::void_pointer;
        using const_void_pointer = typename std::allocator_traits<A>::const_void_pointer;
        using difference_type = typename std::allocator_traits<A>::difference_type;
        using propagate_on_container_copy_assignment = typename std::allocator_traits<A>::propagate_on_container_copy_assignment;
        using propagate_on_container_move_assignment = typename std::allocator_traits<A>::propagate_on_container_move_assignment;
        using propagate_on_container_swap = typename std::allocator_traits<A>::propagate_on_container_swap;
#ifdef __cpp_lib_allocator_traits_is_always_equal
        using is_always_equal = typename std::allocator_traits<A>::is_always_equal;
#endif
        using A::A;
        using size_type = Caped::size_type;
        template <class U>
        struct rebind
        {
            using other = Allocator<typename std::allocator_traits<A>::template rebind_alloc<U>>;
        };
        CONSTEXPR size_type max_size() const noexcept
        {
            using BaseSize = typename std::allocator_traits<A>::size_type;
            static_assert(sizeof(BaseSize) >= sizeof(size_type), "allocator size_type must be bigger than cap type");
            return static_cast<size_type>(std::min<BaseSize>(maxSize, std::allocator_traits<A>::max_size(*this)));
        }
        NODISCARD CONSTEXPR pointer allocate(std::size_t n)
        {
            return n <= max_size() ? std::allocator_traits<A>::allocate(*this, n) : throw std::bad_array_new_length();
        }
#ifdef __cpp_lib_allocate_at_least
        NODISCARD constexpr pointer allocate_at_least(std::size_t n)
        {            
            return n <= max_size() ? std::allocator_traits<A>::allocate_at_least(*this, n) : throw std::bad_array_new_length();
        }
#endif
    };
    template<class T, template <class, class> class V = std::vector, class A = std::allocator<T>>
    struct Vector : V<T, Allocator<A>>
    {
        using Base = V<T, Allocator<A>>;
        using typename Base::value_type;
        using typename Base::allocator_type;
        using typename Base::difference_type;
        using typename Base::reference;
        using typename Base::const_reference;
        using typename Base::pointer;
        using typename Base::const_pointer;
        using typename Base::iterator;
        using typename Base::const_iterator;
        using typename Base::reverse_iterator;
        using typename Base::const_reverse_iterator;
        using Base::Base;
        using Base::assign;
        using Base::insert;
        using size_type = typename allocator_type::size_type;
        CONSTEXPR Vector(size_type count, const T& value, const allocator_type& alloc = allocator_type()) : Base(count, value, alloc){}
#if _MSVC_LANG <= 201402L
        CONSTEXPR explicit Vector(size_type count) : Base(count) {};
        CONSTEXPR explicit Vector(size_type count, const allocator_type& alloc) : Base(count, alloc){}
#else
        CONSTEXPR explicit Vector(size_type count, const allocator_type& alloc = allocator_type()) : V(count, alloc){}
#endif
        CONSTEXPR void assign(size_type count, const T& value) { Base::assign(count, value); }
        CONSTEXPR reference at(size_type pos) { return Base::at(pos); }
        CONSTEXPR const_reference at(size_type pos) const { return Base::at(pos); }
        CONSTEXPR reference operator[](size_type pos) { return Base::operator [](pos); };
        CONSTEXPR const_reference operator[](size_type pos) const { return Base::operator [](pos); };
        CONSTEXPR size_type size() const noexcept { return static_cast<size_type>(Base::size()); }
        CONSTEXPR size_type max_size() const noexcept { return static_cast<size_type>(Base::max_size()); }
        CONSTEXPR size_type capacity() const noexcept { return static_cast<size_type>(Base::capacity()); }
        CONSTEXPR iterator insert(const_iterator pos, size_type count, const T& value) { return Base::insert(pos, count, value); };
        CONSTEXPR void resize(size_type count) { Base::resize(count); };
        CONSTEXPR void resize(size_type count, const value_type& value) { Base::resize(count, value); };
    };
};

戈博尔特片段

相关文章:
  • 没有找到相关文章