Вернуть строку, прочитанную из буфера и функции без динамического выделения?

0

Как я могу возвратить строку, построенную из буфера внутри функции, без динамического выделения памяти?

В настоящее время у меня есть эта функция:

    // 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. Я не думаю, что есть способ обойти это, но я не совсем уверен, возможно ли это.

  • 2
    Я не знаю, что вы ожидаете от new ubyte[]() , но это не разрешено C ++ .
  • 0
    Почему бы не использовать std::vector<ubyte> ? Или basic_string<ubyte> ?
Показать ещё 16 комментариев
Теги:
string
pointers

2 ответа

1
Лучший ответ

Существует не менее трех способов переопределения метода, чтобы избежать прямого распределения с помощью 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;
}

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

5

Лично я бы рекомендовал просто вернуть std::string или std::vector<T>: это аккуратно избегает утечек памяти, и строка не выделяет память для небольших строк (ну, большинство реализаций идут именно так, но не все довольно там).

Альтернативой является создание класса, который может содержать достаточно большой массив и возвращать объект, который имеет тип:

struct buffer {
     enum { maxsize = 16 };
     ubyte buffer[maxsize];
};

Если вы хотите получить больше фантазий и поддерживать более крупные строки, которые тогда просто выделяют память, вам нужно будет немного std::vector<ubyte> с конструкторами, деструкторами и т.д. (Или просто использовать std::vector<ubyte> и перебрать его).

  • 0
    Теперь мне любопытно. Есть ли какие-то реализации, в которых нет единого входа?
  • 0
    @ Крис: конечно. Например, libstc ++: они все еще используют строку COW! Они реализовали строку единого входа, но изменение, сделав ее std::basic_string , произойдет, когда они перейдут к полному соответствию C ++ 11, нарушив ABI (не основных функций языка, а библиотеки) на этом этапе.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню