Есть ли способ ограничения максимального размера в контейнере STL :: map? - PullRequest
1 голос
/ 18 января 2011

Мое приложение может обрабатывать только определенное количество записей в структуре карты, как мне указать это ограничение в моем коде, чтобы мой код не перегружался (из-за отсутствия лучшего термина). Есть ли способ указать максимальный предел при определении переменной типа map?

Спасибо

Ответы [ 3 ]

3 голосов
/ 18 января 2011

Нет никакого способа установить предел при создании экземпляра карты, хотя я предполагал, что вы можете иметь свою собственную безопасную охрану при доступе к ней.Например:

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

Вы можете создать свой собственный класс карты, который инкапсулирует эти проверки.

1 голос
/ 22 января 2011

После того, как мы опробовали идею ограниченного распределителя, я думаю, что гораздо проще собрать std::map (примечание: не наследовать от! По крайней мере, публично) в cappedadaptor.

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();
     }
   }
   ...
};
1 голос
/ 18 января 2011

Контейнеры stl также принимают « allocator » в качестве (по умолчанию) параметра.Этот распределитель является средством контейнера для выделения нового пространства для его данных.

Если вы определите «ограниченный» распределитель (звучит просто, эй?), Вы здесь.

РЕДАКТИРОВАТЬ - ВНа некоторых форумах я обнаружил, что распределители, хотя изначально и предназначались без сохранения состояния, могут быть сохранены на большинстве (современных) компиляторов.Вот почему я продолжаю в этом.Тем не менее, это довольно громоздко, чтобы сделать это таким образом, и, вероятно, гораздо проще и удобнее объединить ваш тип карты в адаптере cappedmap.

Это заняло у меня много моментов здесь и там, но здесь я получилпример компиляции capped, например:

// 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;
}

Примечание: не полностью проверено.Это просто идея.

...