如何将 std::vector 的容量限制为元素的数量
Posted
技术标签:
【中文标题】如何将 std::vector 的容量限制为元素的数量【英文标题】:How to limit the capacity of std::vector to the number of element 【发布时间】:2016-07-18 08:46:35 【问题描述】:我的程序使用 569MB 内存,它只需要使用 500MB, 我有很多不同大小的 std::vector 有没有办法将容量设置为元素的数量以避免内存开销。 (我不关心性能,内存是关键)
【问题讨论】:
不保证能正常工作,您可以使用 shrink_to_fit C++11 函数使向量大到足以容纳数据。 如果std::vector::shrink_to_fit()
功能有帮助,你可以试试。
提升是一种选择吗?然后使用boost.org/doc/libs/1_61_0/doc/html/boost/container/…
@PaulStelian:这可能为时已晚。如果程序限制为 500 MB,操作系统可能会终止进程或拒绝内存分配。当向量变得太大时,后者将变成std::bad_alloc
。
【参考方案1】:
如何将std::vector的容量限制为元素个数
您可以做的最好的事情是在添加元素之前保留所需的空间。这也应该有最好的性能,因为它不会引起重新分配和复制。
如果这不切实际,那么您可以在添加元素后使用std::vector::shrink_to_fit()
。当然,如果分配可能永远不会超过设定的限制,那也无济于事。
从技术上讲,标准都不能保证这两种方法都能将容量与大小相匹配。您依赖于标准库实现的行为。
【讨论】:
v.reserve(n)
保证向量能够容纳 至少 n 个元素,但容量可能大于 n (c++17 23.3.11.3.3),所以根本不能保证避免过头。至于我对 23.3.11.3.9 的解释,即使是 shrink_to_fit 也不能保证 size() == capacity() 之后...
@Aconcagua 好点,我认为在新向量上调用reserve
时有保证,但我显然错了。似乎没有办法保证容量与向量的大小相匹配。我已经更改了答案以反映这一点
在标准下不能保证new char[1000]
也不会分配一个gb,所以unique_ptr
方法没有“保证没有开销”。
@Yakk 哦,亲爱的。你的话我记住了。那么动态内存并没有太多保证,是吗?【参考方案2】:
在向其推送任何内容之前编写一些包装器并控制向量的大小,或者使用固定大小的 std::array 代替
【讨论】:
据我所知,没有办法实现向量的容量等于它的大小。 std::array 会这样做,但您需要在编译时知道最终大小,因为 size 是模板参数并且不能修改大小。如果最坏的情况出现在最坏的情况下,您可能不得不退回到“好”的旧 c++11 之前的数组。不好,但是如果在编译时(最终)大小未知,我看不到另一种保证大小约束的方法......【参考方案3】:您可能正在寻找shrink_to_fit
方法,请参阅http://en.cppreference.com/w/cpp/container/vector/shrink_to_fit。
或者,如果您不能/不允许使用 C++11,您可能需要使用 swap-to-fit 习惯用法:https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Shrink-to-fit
在 C++11 中(注意shrink_to_fit
可能会被编译器忽略):
vector<int> v;
// ...
v.shrink_to_fit();
换装成语:
vector<int> v;
// ...
vector<int>( v ).swap(v);
// v is swapped with its temporary copy, which is capacity optimal
【讨论】:
【参考方案4】:您可以使用自定义分配器并将所需的容量提供给模板参数。从这个线程修改示例: Compelling examples of custom C++ allocators?
#include <memory>
#include <iostream>
#include <vector>
namespace my_allocator_namespace
template <typename T, size_t capacity_limit>
class my_allocator: public std::allocator<T>
public:
typedef size_t size_type;
typedef T* pointer;
typedef const T* const_pointer;
template<typename _Tp1 >
struct rebind
typedef my_allocator<_Tp1 , capacity_limit> other;
;
pointer allocate(size_type n, const void *hint=0)
if( n > capacity_limit )
return std::allocator<T>::allocate(capacity_limit );
return std::allocator<T>::allocate(n, hint);
void deallocate(pointer p, size_type n)
return std::allocator<T>::deallocate(p, n);
my_allocator() throw(): std::allocator<T>()
my_allocator(const my_allocator &a) throw(): std::allocator<T>(a)
template <class U,size_t N>
my_allocator(const my_allocator<U,N> &a) throw(): std::allocator<T>(a)
~my_allocator() throw()
;
using namespace std;
using namespace my_allocator_namespace;
int main()
vector<int, my_allocator<int,20> > int_vec(10);
for(int i = 0 ;i < 20; i++)
std::cerr << i << "," << int_vec.size() << std::endl;
int_vec.push_back(i);
但是在访问超出范围的索引时应该小心
【讨论】:
以上是关于如何将 std::vector 的容量限制为元素的数量的主要内容,如果未能解决你的问题,请参考以下文章
使用 std::vector 时如何将索引信息传递给元素构造函数?
在 64 位上调整 std::vector 大小的 bad_alloc 错误。它似乎将其限制为 32 位
即使根据容量()仍有未使用的空间,std::vector 能否将其数据移动到 emplace_back()处的另一个地址?