Что относительно <meta>
и <link>
? Почему они не находятся в том списке?
Быстрое эмпирическое правило, не самозакрывайте элемент, который предназначается для имения содержания, потому что это определенно вызовет проблемы браузера рано или поздно.
Те, которые являются естественно закрывающимися автоматически, как <br>
и <img>
, должны быть очевидными. Те, которые не являются... просто, не самозакрывают их!
Вам нужен 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
гарантированно будет непрерывным.
std :: string
подойдет для этого:
append ()
с указателем и длиной. data ()
, и текущую длину, вызвав size ()
или length ()
на нем. clear ()
, чтобы стереть его содержимое, не уничтожая его. std::vector<unsigned char> buffer;
Каждый push_back будет добавлять новый символ в конце (при необходимости перераспределяя). Вы можете вызвать резерв, чтобы минимизировать количество распределений, если вы приблизительно знаете, сколько данных вы ожидаете.
buffer.reserve(1000000);
Если у вас есть что-то вроде этого:
unsigned char buffer[1000];
std::vector<unsigned char> vec(buffer, buffer + 1000);
Еще один голос за 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], если вы используете буфер строка)
Я бы посмотрел на Boost basic_streambuf , который разработан для таких целей. Если вы не можете (или не хотите) использовать Boost, я бы рассмотрел вариант std :: basic_streambuf
, который очень похож, но требует немного больше работы. В любом случае вы в основном наследуете этот базовый класс и перегружаете underflow ()
для чтения данных из сокета в буфер. Обычно вы присоединяете std :: istream
к буферу, чтобы другой код читал из него примерно так же, как если бы пользователь вводил его с клавиатуры (или чего-то еще).
Альтернатива, которая не из STL, но может быть полезна - Boost.Circular buffer
Используйте std :: vector , растущий массив, который гарантирует непрерывность хранилища (ваша третья точка).
Что касается вашего комментария «Я не вижу append ()», вставка в конце - это то же самое.
vec.insert (vec.end,
Если вы действительно используете std :: vector, вы просто используете его для управления необработанной памятью для вас.
Вы можете просто malloc
самый большой буфер, который, по вашему мнению, вам понадобится, и отслеживать смещение записи / общее количество прочитанных байтов (это одно и то же).
Если вы дойдете до конца ... либо realloc
, либо выберете способ отказа.
Я знаю, это не совсем C ++ y, но это простая проблема и другие предложения кажутся тяжелыми способами ввести ненужную копию.