Как я могу возвратить строку, построенную из буфера внутри функции, без динамического выделения памяти?
В настоящее время у меня есть эта функция:
// Reads null-terminated string from buffer in instance of buffer class.
// uint16 :: unsigned short
// ubyte :: unsigned char
ubyte* Readstr( void ) {
ubyte* Result = new ubyte[]();
for( uint16 i = 0; i < ByteSize; i ++ ) {
Result[ i ] = Buffer[ ByteIndex ];
ByteIndex ++;
if ( Buffer[ ByteIndex - 1 ] == ubyte( 0 ) ) {
ByteIndex ++;
break;
};
};
return Result;
};
Хотя я могу вернуть построенную строку, я не могу сделать это без динамического выделения. Это становится проблемой, если вы считаете следующее использование:
// Instance of buffer class "Buffer" calling Readstr():
cout << Buffer.Readstr() << endl;
// or...
ubyte String[] = Buffer.String();
Использование, подобное этому вызову, приводит к той же утечке памяти, что и данные не удаляются с помощью delete
. Я не думаю, что есть способ обойти это, но я не совсем уверен, возможно ли это.
Существует не менее трех способов переопределения метода, чтобы избежать прямого распределения с помощью new
.
Используйте std::vector
(это будет выделение памяти кучи):
std::vector<ubyte> Readstr()
{
std::vector<ubyte> Result;
for (uint16 i = 0; i < ByteSize; i++)
{
Result.push_back(Buffer[ByteIndex]);
ByteIndex++;
if (Buffer[ByteIndex - 1] == ubyte(0))
{
ByteIndex++;
break;
}
}
return Result;
}
Заставить вызывающего абонента предоставлять выходной буфер и, возможно, размер, чтобы избежать переполнения (не выделяет напрямую память):
ubyte* Readstr(ubyte* outputBuffer, size_t maxCount)
{
for (uint16 i = 0; i < ByteSize; i++)
{
if (i == maxCount)
break;
outputBuffer[i] = Buffer[ByteIndex];
ByteIndex++;
if (Buffer[ByteIndex - 1] == ubyte(0))
{
ByteIndex++;
break;
}
}
return outputBuffer;
}
Используйте внутренний статический массив и верните ссылку на него:
ubyte* Readstr()
{
enum { MAX_SIZE = 2048 }; // Up to you to decide the max size...
static ubyte outputBuffer[MAX_SIZE];
for (uint16 i = 0; i < ByteSize; i++)
{
if (i == MAX_SIZE)
break;
outputBuffer[i] = Buffer[ByteIndex];
ByteIndex++;
if (Buffer[ByteIndex - 1] == ubyte(0))
{
ByteIndex++;
break;
}
}
return outputBuffer;
}
Имейте в виду, что этот последний параметр имеет несколько ограничений, включая возможность расследований данных в многопоточном приложении и невозможность вызвать его внутри рекурсивной функции, среди других тонких проблем. Но в остальном, возможно, наиболее близкое к тому, что вы ищете, и можете безопасно использовать его, если принять некоторые меры предосторожности и сделать некоторые предположения о вызывающем коде.
Лично я бы рекомендовал просто вернуть std::string
или std::vector<T>
: это аккуратно избегает утечек памяти, и строка не выделяет память для небольших строк (ну, большинство реализаций идут именно так, но не все довольно там).
Альтернативой является создание класса, который может содержать достаточно большой массив и возвращать объект, который имеет тип:
struct buffer {
enum { maxsize = 16 };
ubyte buffer[maxsize];
};
Если вы хотите получить больше фантазий и поддерживать более крупные строки, которые тогда просто выделяют память, вам нужно будет немного std::vector<ubyte>
с конструкторами, деструкторами и т.д. (Или просто использовать std::vector<ubyte>
и перебрать его).
std::basic_string
, произойдет, когда они перейдут к полному соответствию C ++ 11, нарушив ABI (не основных функций языка, а библиотеки) на этом этапе.
new ubyte[]()
, но это не разрешено C ++ .std::vector<ubyte>
? Илиbasic_string<ubyte>
?