Лучший способ обернуть символ * в C ++? - PullRequest
0 голосов
/ 22 апреля 2019

В моем коде я использую буферы, расположенные в данный момент следующим образом:

char* buf1 = (char*)malloc(size);

Однако в некоторых местах кода я хочу переназначить указатель на другое место в памяти.Проблема в том, что есть другие места в коде, которые все еще должны иметь доступ к указателю buf1.

Какой лучший способ сделать это в C ++?Прямо сейчас я рассматриваю возможность написать структуру с одним символом *, затем выделить объект этого типа структуры и передать его туда, где мне нужно, и обратиться к свернутому указателю, чтобы получить текущее значение buf1.

Однако, похоже, это похоже на то, что делает unique_ptr.Если я использую unique_ptr, как я могу обернуть в него символ *?У меня были некоторые проблемы с тестированием, и я не уверен, что оно поддерживается.

Чтобы уточнить: эти буферы являются байтами различного размера.

1 Ответ

3 голосов
/ 22 апреля 2019

В общем, на этот вопрос нельзя ответить. Есть просто слишком много вещей, которые вы можете захотеть делать с массивом char. Не зная, что на самом деле вы хотите сделать, невозможно сказать, какие хорошие абстракции можно использовать & hellip;

Если вы хотите что-то делать со строками, просто используйте std::string. Если вам нужен динамический размер буфера, который может увеличиваться и уменьшаться, используйте std::vector.

Если вам просто нужен байтовый буфер, размер которого определяется во время выполнения или который вы просто хотите использовать в динамическом хранилище, я бы выбрал std::unique_ptr. В то время как std::unique_ptr<T> только для отдельных объектов, частичная специализация std::unique_ptr<T[]> может использоваться для работы с динамически размещаемыми массивами. Например:

auto buffer = std::unique_ptr<char[]> { new char[size] };

Как правило, рекомендуемый способ создания объекта с помощью new и получения std::unique_ptr к нему заключается в использовании std :: make_unique . И если вы хотите, чтобы ваш буфер инициализировался к какому-то конкретному значению, вы действительно должны использовать std::make_unique<char[]>(value). Однако std::make_unique<T[]>() будет инициализировать значение элементов массива, которые он создает. В случае массива char это фактически означает, что ваш массив будет инициализирован нулем. По моему опыту, компиляторы, к сожалению, не могут оптимизировать нулевую инициализацию, даже если сразу после создания весь буфер будет перезаписан. Поэтому, если вы хотите использовать неинициализированный буфер, чтобы избежать накладных расходов на инициализацию, вы не можете использовать std::make_unique. В идеале вы должны просто определить свою собственную функцию для создания инициализированного по умолчанию массива с помощью new и получить std::unique_ptr к нему, например:

template <typename T>
inline std::enable_if_t<std::is_array_v<T> && (std::extent_v<T> == 0), std::unique_ptr<T>> make_unique_default(std::size_t size)
{
    return std::unique_ptr<T> { new std::remove_extent_t<T>[size] };
}

, а затем

auto buffer = make_unique_default<char[]>(new char[size]);

Похоже, что C ++ 20 будет включать эту функциональность в виде std::make_unique_default_init. Так что тогда это будет предпочтительный метод.

Обратите внимание, что если вы имеете дело с простым std::unique_ptr, вам все равно придется отдельно передавать размер буфера. Возможно, вы захотите связать std::unique_ptr и std::size_t, если вы планируете обойти буфер

template <typename T>
struct buffer_t
{
    std::unique_ptr<T[]> data;
    std::size_t size;
};

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

buffer_t makeMeABuffer();

или передача права собственности на буфер кому-либо еще, например,

DataSink(buffer_t&& buffer)

Вы не захотите использовать его просто для указания какой-либо функции на данные буфера, а размер выполняет некоторую обработку без передачи права собственности. Для этого вам нужно просто передать указатель и размер или, например, использовать span (начиная, опять же, с C ++ 20; также доступен как часть GSL ) & hellip;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...