В каких случаях возникает потребность использования raw pointers в современном C++?

326
18 февраля 2017, 06:17

После появления новых возможностей в C++ таких как std::make_shared() и std::make_unique то возникает вопрос : А есть ли хоть один случай, когда действительно нужно работать с сырым указателем?

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

Я беру среднего по уровню программиста на C++. Он пишет свою библиотеку без использования сторонего кода. И у меня не находится ни одного примера, когда ему действительно нужно пользоваться сырыми указателями.

Answer 1

Во внутренних деталях реализации, когда владеющие указатели усложняют взаимодействие, когда нужно разделять владение, но время жизни объекта чётко детерминировано и не возникает вопроса: где и когда чистить объект (shared_ptr в таких случаях - лишнее), когда ссылкой не обойтись, потому как возможна ситуация с nullptr у объекта. В публичных API стараться избегать, пока это возможно, либо чётко обосновывать - "почему?" и "зачем?".

В общем, я придерживаюсь правила: обходиться без сырых указателей, пока это возможно. Пока не подводило (embedded).

Кстати, возможно забавно, но в C проектах, при достижении определённого уровня сложности, тоже начинают появляются механизмы разделяемого владения. Это всем известные xxx_ref(object)/xxx_unref(object). Примеры: GLib со своим gobject, FFmpeg активно внедряет подсчёт ссылок для AVPacket и AVFrame (для таких случаев в Boost существует intrusive_ptr), ядро Linux тоже не стоит в стороне (https://lwn.net/Articles/336224/ по слову Reference Counting или http://www.makelinux.net/books/lkd2/ch17lev1sec7) со своим kobject.

Answer 2

Самый банальный пример — дерево. Каждый узел хранит родителя. Можно, конечно, хранить в weak_ptr, но это не удобно и, на мой взгляд, глупо. Поэтому в этом случае используется «голый» указатель. Можно придумать и другие примеры, но суть их будет следующая: «голые» указатели, в современном коде, можно и нужно использовать тогда, когда мы не владеем тем, на что ссылаемся и у нас есть уверенность, что то, на что мы ссылаемся не «умрёт» раньше, чем мы.

На эту тему есть отличное видео от Страуструпа: Writing Good C++14. Львиная его доля посвящена именно указателям.

Answer 3

Упомянутые "умные" указатели являются владеющими. Т.е. при вызове деструктора умного указателя данные либо освобождаются сразу (std::unique_ptr), либо уменьшается счетчик владения (std::shared_ptr), и при достижении нуля осуществляется освобождение данных.

Если же указатель не владеет данными как раз имеет смысл использовать сырые указатели. Небольшое исключение это std::weak_ptr - невладеющий указатель, но полученный из std::shared_ptr.

Чаще всего наверное использовать сырые указатели приходится при взаимодействии со старым (до C++11) кодом или вовсе Си-кодом. Например, работа со строками char*.

Answer 4

Хотите простейший пример? :)

int main(int , char**)

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

Answer 5

Те же std::shared_ptr<T> занимают в два раза больше памяти (из-за указателя на счетчик). Для структур (деревьев, например), активно использующих указатели, это может быть значительной добавкой. Да и передача их по значению - это копирование в стек в два раза большего объёма данных. Да, в больших проектах часто не так заметно будет это потребление памяти, но бывают и исключительные ситуации.

READ ALSO
запрос на откат даты поста на сайте mysql

запрос на откат даты поста на сайте mysql

ЗдравствуйтеМожно ли сгенерировать sql запрос таким образом, чтобы все сообщения на форуме были датированы 2011 годом? Форум основан на mybb

331
Sql запрос поиска в дереве

Sql запрос поиска в дереве

Нужно составить sql запрос, с помощью которого можно узнать входит ли пользователь в ветку партнёров

382
left-right join

left-right join

Сделал тройной left/right join, чтобы вывести в трех колонках результаты трех запросов

372