Производная от std :: vector <> с помощью resize (), которая не инициализирует примитивы и не пересылает construct_back - PullRequest
1 голос
/ 07 марта 2012

Итак, есть масса случаев, когда это требовалось в приложениях, чувствительных к производительности, и я наконец-то оказался на соломинке, которая сломала верблюдов.Он должен быть скомпилирован в C ++ 98, так как по крайней мере одна из наших платформ гарантирует только соответствие C ++ 98.

Отредактировано, надеюсь, будет немного яснее с тем, что я хочу.

Пример:

// This will allocate storage for 1024, and then loop 1024 times touching all of it just to place a 0 in it 
std::vector< char > buffer( 1024 );
// Now read will write into that buffer, overwriting the 0s ( we payed for the fill unnecessarily ) 
buffer.resize( read( someSource, &buffer[0], buffer.size() ) );

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

// Disabled for anything which doesn't pass boost::is_POD< T >, they get the standard version
void resize( size_t a_NewSize )
{
     reserve( a_NewSize );
     _end = _begin + a_NewSize;
}

construct_back будет конструктором пересылки, для 1 константного аргумента это будет выглядеть примерно так (непроверено):

template< typename T1 >
void construct_back( const T1& a_Arg1 )
{
    if( capacity() <= size() ) // No room
         reserve( size() + 1 );
    // Construct in place using Ts constructor that accepts const T1&
    new (&(*end()) T( T1 );
    ++_end; // Account for new element
}

construct_backдолжно иметь все возможное количество аргументов ^ 2 перегрузки, это общий метод грубой силы для идеальной пересылки в C ++ 98.

Ответы [ 3 ]

3 голосов
/ 07 марта 2012

Для предварительного выделения памяти в векторе используйте vector::reserve.Это будет работать не только для примитивных типов, но и для всех типов.

Для создания элементов на месте вам нужно будет использовать C ++ 11 с vector::emplace_back или один из контейнеров, предоставленных Boost.Containers..

Если вам нужна ленивая конструкция (потому что ваши конструкторы дороги), std::vector<boost::optional> - хорошее решение.

1 голос
/ 09 марта 2012

Ваш компилятор может быть достаточно умен, чтобы избежать инициализации. (Если он встроен во все, и вы используете этот вектор только локально, это не слишком сложно сделать вывод, что инициализация устарела.)

В противном случае:

Если вам так важна производительность, и если у вас все равно есть буфер фиксированного размера, почему бы просто не использовать массив в стеке? I.e.:

char buffer[1024];
size_t blen = read( someSource, buffer, sizeof(buffer) );

Вы также избегаете косвенного обращения к куче, введенной std::vector в этом случае.

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

template<typename T = char, size_t MaxSize = 1024>
struct Buffer {
    static const size_t maxsize = MaxSize;
    typedef T type;
    type data[maxsize];
    size_t len;
    Buffer() : len(0) {}
};

И вставьте туда любые другие функции, которые вам нужны (чтобы они были похожи на STL-контейнеры).

0 голосов
/ 07 марта 2012
v1.reserve( 200 );

использование резерва может уменьшить количество изменения размера узнать больше о резерве на MSDN

...