【问题标题】:Is there a way to cap the max size on a STL::map container?有没有办法限制 STL::map 容器的最大大小?
【发布时间】:2011-01-18 19:35:37
【问题描述】:

我的应用程序最多只能处理映射结构中的一定数量的条目,我如何在我的代码中指定该限制,以便我的代码不会被淹没(因为缺乏更好的术语)。定义map类型的变量时有没有办法指定最大限制?

谢谢

【问题讨论】:

  • 除了不将超过 N 个元素放入地图之外?

标签: c++ stl map size max


【解决方案1】:

在实例化地图时无法设置限制,尽管我认为您在访问地图时可以拥有自己的安全防护。例如:

if (mymap.find(a) == mymap.end() and mymap.size() >= MAX_MAP_ALLOWED) {
    throw (runtime_error("map limit exceeded"));
} else {
    mymap[a] = b;
}

您可以创建自己的地图类来封装这些检查。

【讨论】:

    【解决方案2】:

    stl 容器还采用“allocator”作为(默认)参数。这个分配器是容器为其数据分配新空间的手段。

    如果您定义一个“封顶”分配器(听起来很简单,嘿?),您就在那里。

    编辑 - 在某些论坛中,我发现分配器虽然最初是无状态的,但在大多数(现代)编译器上可以是有状态的。这就是为什么我继续这样做。但是,这样做很麻烦,而且可能更容易和更易于将您的地图类型聚合到 cappedmap 适配器中。

    我在这里和那里花了很多时间,但在这里我得到了一个编译、加盖的示例:

    // an allocator with maximally MAX elements.
    template< typename T, size_t MAX = 5 >
    struct AllocateCapped {
    
        // reuses an existing allocator
        typedef std::allocator<T> tallocator;
    
        typedef typename tallocator::value_type value_type;
        typedef typename tallocator::pointer pointer;
        typedef typename tallocator::reference reference;
        typedef typename tallocator::const_pointer const_pointer;
        typedef typename tallocator::const_reference const_reference;
        typedef typename tallocator::size_type size_type;
        typedef typename tallocator::difference_type difference_type;
    

    上限分配器的实际代码委托给allocator成员:

        size_t free;
        tallocator allocator;
    
        AllocateCapped():free(MAX){
            printf("capped");
        }
    
    template<typename T2>
        AllocateCapped( const AllocateCapped<T2>& other ){}
    
        pointer allocate( size_type n, const_pointer hint = 0) {
            if( !free ) throw std::bad_alloc();
            free-=n;
            return allocator.allocate( n, hint );
        }
    
        void deallocate( pointer p, size_type n ) {
            free+=n;
            allocator.deallocate(p,n);
        }
    
        size_type max_size() const { return free; }
        void construct( pointer p, const_reference val ) {
            return allocator.construct(p,val);
        }
        void destroy( pointer p ) { allocator.destroy(p); }
    
        template<class _Other>
        struct rebind 
        {   // convert this type to _ALLOCATOR<_Other>
            typedef typename AllocateCapped<_Other> other;
        };
    
    };
    

    这个分配器可以这样使用:

    // example structure
    struct s {
        int i;
        s():i(){}
        s(int i):i(i){}
    };
    
    int main(int argc, char* argv[]) {
    typedef AllocateCapped< std::pair<const int, s> > talloc;
    talloc a;
    talloc::pointer p = reinterpret_cast<talloc::pointer>( a.allocate(1,0) );
    a.construct(p, talloc::value_type() );
    a.destroy(p);
    a.deallocate(p, 1 );
    
    std::map<int , s, std::less<int>, talloc > m;
    std::vector<int, AllocateCapped<int> > v;
    for( int i = 0; i != 4; ++i ) {
        m[i]=s(i);
        v.push_back(i);
    }
    m[5]=s(5); // throws
    v.push_back(5); // throws
    return 0;
    }
    

    注意:未经彻底测试。这只是一个想法。

    【讨论】:

    • 有趣。用户是否必须覆盖max_size()?
    • 不幸的是,分配器不是针对每个容器的,因此除非您对要限制其大小的地图的每个实例都有单独的分配器类型,否则这种方法是行不通的。
    • @James:可以使用特殊分配器将typedef 和map。
    • @james:我不同意:我知道的 map 构造函数 (cplusplus.com/reference/stl/map/map) 将分配器对象作为参数。
    • @xtofl:确实如此,但分配器规范中有一个要求,即“给定分配器类型的所有实例都必须是可互换的,并且总是相互比较相等。”由于分配器实例必须是可互换的,容器不需要存储你给它的分配器;它可以默认构造另一个相同类型的分配器(或者它可以复制分配器并使用它们,或者它可以进行各种其他优化)。
    【解决方案3】:

    在尝试了上限分配器的想法后,我认为在cappedadaptor 中聚合std::map(注意:不是继承自!至少不公开)更简单。

    template<typename tKey, typename tVal> class cappedmap {
       typedef std::map<tKey,tVal> tmap;
       tmap mymap;
    
       cappedmap(size_t amax):mymax(amax){}
    
       // adapt the map interface
       pair<tmap::iterator,bool> insert( tmap::value_type kv ) { 
            if( mymap.size() > mymax ) throw myexcept();
            return mymap.insert(kv);
       }
    
       tVal operator[]( tKey k ) { 
         tVal v = mymap[k];
         if( mymap.size() > mymax ) { 
            mymap.remove(k)
            throw myexcept();
         }
       }
       ...
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-29
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 2010-12-10
      相关资源
      最近更新 更多