恒定大小的矢量
Constant-sized vector
有人知道定义常量大小向量的方法吗?
例如,而不是定义
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>
),但你希望能够在0
和N
之间用不同数量的元素填充向量,那么一个不错的选择是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,而 vector
和 fixed_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); };
};
};
戈博尔特片段
- 没有找到相关文章