如何将 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 的容量限制为元素的数量的主要内容,如果未能解决你的问题,请参考以下文章

vector

使用 std::vector 时如何将索引信息传递给元素构造函数?

在 64 位上调整 std::vector 大小的 bad_alloc 错误。它似乎将其限制为 32 位

如何安全地引用 std::vector 元素?

即使根据容量()仍有未使用的空间,std::vector 能否将其数据移动到 emplace_back()处的另一个地址?

将一行 cv::Mat 转换为 std::vector