Динамический буферный тип в C++?

Что относительно <meta> и <link>? Почему они не находятся в том списке?

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

Те, которые являются естественно закрывающимися автоматически, как <br> и <img>, должны быть очевидными. Те, которые не являются... просто, не самозакрывают их!

25
задан Jacob 9 December 2009 в 17:11
поделиться

9 ответов

Вам нужен std :: vector :

std::vector<char> myData;

vector автоматически выделит и освободит свою память за вас. Используйте push_back , чтобы добавить новые данные ( вектор изменит размер при необходимости), и оператор индексации [] для извлечения данных.

Если в какой-то момент вы можете догадаться, как много памяти вам понадобится, я предлагаю вызвать резерв , чтобы последующим push_back не пришлось перераспределять столько же.

Если вы хотите прочитать фрагмент памяти и добавьте ее в свой буфер, проще всего было бы что-то вроде:

std::vector<char> myData;
for (;;) {
    const int BufferSize = 1024;
    char rawBuffer[BufferSize];

    const unsigned bytesRead = get_network_data(rawBuffer, sizeof(rawBuffer));
    if (bytesRead <= 0) {
        break;
    }

    myData.insert(myData.end(), rawBuffer, rawBuffer + bytesRead);
}

myData теперь имеет все прочитанные данные, чтение фрагмент за фрагментом. Однако мы копируем дважды.

Вместо этого мы попробуем что-то вроде этого:

std::vector<char> myData;
for (;;) {
    const int BufferSize = 1024;

    const size_t oldSize = myData.size();
    myData.resize(myData.size() + BufferSize);        

    const unsigned bytesRead = get_network_data(&myData[oldSize], BufferSize);
    myData.resize(oldSize + bytesRead);

    if (bytesRead == 0) {
        break;
    }
}

Которая считывается непосредственно в буфер за счет периодического перераспределения.

Это можно сделать умнее, например, удвоив размер вектора для каждого изменения размера, чтобы амортизировать изменения размера, как первое решение неявно. И, конечно, вы можете зарезервировать () гораздо больший буфер заранее, если у вас есть априорное знание вероятного размера окончательного буфера, чтобы минимизировать изменения размеров.

Оба варианта оставлены в качестве упражнения для читатель. :)

Наконец, если вам нужно обрабатывать данные как необработанный массив:

some_c_function(myData.data(), myData.size());

std :: vector гарантированно будет непрерывным.

И, конечно же, вы можете зарезервировать () гораздо больший буфер заранее, если у вас есть априорное знание вероятного размера окончательного буфера, чтобы минимизировать изменения размеров.

Оба варианта оставлены в качестве упражнения для читатель. :)

Наконец, если вам нужно обрабатывать данные как необработанный массив:

some_c_function(myData.data(), myData.size());

std :: vector гарантированно будет непрерывным.

И, конечно, вы можете зарезервировать () гораздо больший буфер заранее, если у вас есть априорное знание вероятного размера окончательного буфера, чтобы минимизировать изменения размеров.

Оба варианта оставлены в качестве упражнения для читатель. :)

Наконец, если вам нужно обрабатывать данные как необработанный массив:

some_c_function(myData.data(), myData.size());

std :: vector гарантированно будет непрерывным.

39
ответ дан 28 November 2019 в 18:11
поделиться

std :: string подойдет для этого:

  • Он поддерживает встроенные нули.
  • Вы можете добавить к нему многобайтовые блоки данных, вызвав append () с указателем и длиной.
  • Вы можете получить его содержимое в виде массива символов, вызвав для него data () , и текущую длину, вызвав size () или length () на нем.
  • Освобождение буфера выполняется автоматически деструктором, но вы также можете вызвать на нем clear () , чтобы стереть его содержимое, не уничтожая его.
7
ответ дан 28 November 2019 в 18:11
поделиться
std::vector<unsigned char> buffer;

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

buffer.reserve(1000000);

Если у вас есть что-то вроде этого:

unsigned char buffer[1000];
std::vector<unsigned char> vec(buffer, buffer + 1000);
9
ответ дан 28 November 2019 в 18:11
поделиться

Еще один голос за std :: vector. Минимальный код, пропускает лишнюю копию GMan code do:

std::vector<char> buffer;
static const size_t MaxBytesPerRecv = 1024;
size_t bytesRead;
do
{
    const size_t oldSize = buffer.size();

    buffer.resize(oldSize + MaxBytesPerRecv);
    bytesRead = receive(&buffer[oldSize], MaxBytesPerRecv); // pseudo, as is the case with winsock recv() functions, they get a buffer and maximum bytes to write to the buffer

    myData.resize(oldSize + bytesRead); // shrink the vector, this is practically no-op - it only modifies the internal size, no data is moved/freed
} while (bytesRead > 0);

Что касается вызова функций WinAPI - используйте & buffer [0] (да, это немного неуклюже, но так оно и есть), чтобы передать аргументы char *, buffer .size () как длина.

И последнее замечание: вы можете использовать std :: string вместо std :: vector, никакой разницы быть не должно (за исключением того, что вы можете написать buffer.data () вместо & buffer [0], если вы используете буфер строка)

6
ответ дан 28 November 2019 в 18:11
поделиться

Я бы посмотрел на Boost basic_streambuf , который разработан для таких целей. Если вы не можете (или не хотите) использовать Boost, я бы рассмотрел вариант std :: basic_streambuf , который очень похож, но требует немного больше работы. В любом случае вы в основном наследуете этот базовый класс и перегружаете underflow () для чтения данных из сокета в буфер. Обычно вы присоединяете std :: istream к буферу, чтобы другой код читал из него примерно так же, как если бы пользователь вводил его с клавиатуры (или чего-то еще).

4
ответ дан 28 November 2019 в 18:11
поделиться

Альтернатива, которая не из STL, но может быть полезна - Boost.Circular buffer

2
ответ дан 28 November 2019 в 18:11
поделиться

Используйте std :: vector , растущий массив, который гарантирует непрерывность хранилища (ваша третья точка).

1
ответ дан 28 November 2019 в 18:11
поделиться

Что касается вашего комментария «Я не вижу append ()», вставка в конце - это то же самое.

vec.insert (vec.end,

0
ответ дан 28 November 2019 в 18:11
поделиться

Если вы действительно используете std :: vector, вы просто используете его для управления необработанной памятью для вас. Вы можете просто malloc самый большой буфер, который, по вашему мнению, вам понадобится, и отслеживать смещение записи / общее количество прочитанных байтов (это одно и то же). Если вы дойдете до конца ... либо realloc , либо выберете способ отказа.

Я знаю, это не совсем C ++ y, но это простая проблема и другие предложения кажутся тяжелыми способами ввести ненужную копию.

0
ответ дан 28 November 2019 в 18:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: