Установите shared_ptr с new_pointer, который является old_pointer + offset

Вот умный указатель: std::shared_ptr<char> p(new char[size]) который представляет массив, заполненный необработанным содержимым двоичного файла. После (и только после) весь массив копируется из файла в ОЗУ, я могу его проанализировать, и во время этого я получаю некоторую информацию заголовка (несколько первых двойных слов). Затем следуют фактические данные.

Не предоставляя намного больше контекста, мне удобно установить упомянутый общий указатель на новый адрес, который является началом фактических данных. Этот адрес все еще находится в выделенной памяти. Но как установить, не потеряв его?

Вопрос (да/нет): возможно ли установить p на смещение превалирующего указателя, не вызывая удаления данных?

Ответы

Ответ 1

Да, это возможно. Вы можете использовать конструктор 8, конструктор псевдонимов из этой ссылки: https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

// make sure you use an array deleter
std::shared_ptr<char> osp(new char[1024], std::default_delete<char[]>());

// load the data into your buffer at osp.get()

// Find the offset in the data by parsing
auto const offset = parse_buffer_for_offset(osp.get());

// Now set a new offset into the data
std::shared_ptr<char> nsp(osp, osp.get() + offset);

Теперь nsp.get() возвращает адрес смещения, но исходный массив будет удален должным образом.

Примечание. Смещение является свойством каждого shared_ptr поэтому, если вы скопируете shared_ptr nsp вы получите еще один shared_ptr с тем же смещением. Это работает независимо от того, создаете ли вы новую копию или присваиваете копию существующему shared_ptr.

Это означает, что вы можете иметь разные shared_ptr с разными смещениями, которые управляют одним и тем же базовым ресурсом, который будет очищен только после уничтожения всех shared_ptr.

Чтобы увидеть это в действии, рассмотрите следующий код:

std::shared_ptr<char> original_sp(new char[1024], std::default_delete<char[]>());

std::shared_ptr<char> offset_100_sp1(original_sp, original_sp.get() + 100);
std::shared_ptr<char> offset_100_sp2 = offset_100_sp1;

std::shared_ptr<char> offset_200_sp1(original_sp, original_sp.get() + 200);
std::shared_ptr<char> offset_200_sp2 = offset_200_sp1;

std::cout << "\nPointers managing the array: " << original_sp.use_count() << '\n';

std::cout << "\nOffset 100 pointers:" << '\n';
std::cout << std::distance(original_sp.get(), offset_100_sp1.get()) << '\n';
std::cout << std::distance(original_sp.get(), offset_100_sp2.get()) << '\n';

std::cout << "\nOffset 200 pointers:" << '\n';
std::cout << std::distance(original_sp.get(), offset_200_sp1.get()) << '\n';
std::cout << std::distance(original_sp.get(), offset_200_sp2.get()) << '\n';

Выход:

Pointers managing the array: 5

Offset 100 pointers:
100
100

Offset 200 pointers:
200
200