Использование неумных указателей в современном C++

Укороченная версия:
Есть ли приемлемая причина для использования неумных указателей в современном C++?

Длинная версия:
У нас есть огромный продукт, который содержит много старого кода C++, и теперь мы пытаемся реорганизовать его в современную эпоху C++. Наряду со всем старомодным кодом существует огромное количество указателей (в основном с аннотациями SAL для обеспечения некоторого чувства безопасности), и мне было интересно, стоит ли нам менять их все на умные указатели или, возможно, оставить некоторые из них как есть.?
Пытаясь преобразовать некоторые из этих кодов, я получил код, за который просто можно спорить, используя умные указатели.

Итак, вопрос в том, существует ли такая вещь, как использование интеллектуальных указателей?
Или, другими словами: есть ли приемлемый сценарий для неумных указателей в наши дни?

5 ответов

Умные указатели (unique_ptr а также shared_ptr) должны быть СОБСТВЕННЫМИ указателями (т. е. ответственными за уничтожение объекта). Суть их использования в том, что любой объект, созданный new следует засунуть в unique_ptr Как можно скорее, чтобы предотвратить утечки памяти. После этого unique_ptr должно закончиться перемещением:

  • либо в shared_ptr если право собственности должно быть разделено,
  • или в unique_ptr если владение определяется областью действия (блока или времени жизни объекта).

releaseс должно быть редко. Если ваш код обходит не владеющие указателями, это должно быть:

  • сырые указатели, если они могут быть null(получено get)
  • ссылки, если они не могут быть null(получено get)
  • unique_ptrs по значению, если целью вызова является передача права собственности. (в этом случае вам нужно будет их переместить)

Заводские методы должны возвращаться unique_ptrс по значению. (потому что тогда, если вы не назначите возвращаемое значение фабричного метода, объект будет немедленно отменен)

И ознакомьтесь с ответом Али относительно ссылок на некоторые философские аспекты работы с унаследованным кодом. (С чем я полностью согласен)

Укороченная версия:
Есть ли приемлемая причина для использования неумных указателей в современном C++?

Короткий ответ:

Определенно, если они служат только для наблюдения, то есть они не владеют pointee. Тем не менее, попробуйте использовать ссылки вместо указателей даже в этом случае; используйте указатели, только если вам действительно нужно сделать их необязательными (инициализировать с помощью null_ptr затем переназначить позже, например).

Длинная версия:
У нас есть огромный продукт, который содержит много старого кода C++, и теперь мы пытаемся реорганизовать его в современную эпоху C++. [...]

Длинный ответ:

Когда я читаю эти строки, мне приходит в голову ответ:

Хотелось бы, чтобы я мог проголосовать за этот ответ более одного раза. Я бы процитировал: "[...] для каждого сделанного нами повторного фактора мы можем обосновать, что" это конкретное изменение сделает реальную задачу, которую мы сейчас выполняем, легче ". Вместо" это теперь чище для будущей работы "."

Короче говоря, не делайте большой рефакторинг, если вам действительно не нужно.

Итак, вопрос в том, существует ли такая вещь, как использование интеллектуальных указателей?

По моему мнению, std::shared_ptr чрезмерно используется. Его очень удобно использовать, и это создает у вас иллюзию, что вам не нужно думать о правах собственности. Но это не вся картина. Я полностью согласен с Шоном Родителем: "разделяемый указатель так же хорош, как и глобальная переменная". Общие указатели также могут создавать очень сложные проблемы с владением и т. Д.

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

Интересные разговоры Шона Родителя о том, как избежать / уменьшить использование указателей:

Надеюсь это поможет.

Да, необработанные указатели все еще используются в качестве "необязательной ссылки". Т.е. T* похож на T&, Ни подразумевает владение, но T* может быть nullptr,

Конечно, в современном C++ есть варианты использования для необработанных указателей:

  • интерфейсы, которые должны быть компилируемыми как чистый C (хотя сама реализация может использовать те функции C++, которые также не являются функциями C, такими как классы или интеллектуальные указатели)
  • код очень низкого уровня, настолько низкого уровня, что даже самый простой смарт-указатель оказывается слишком тяжелым

Конечно, это довольно редкие случаи, и для большинства случаев использования указателей умные указатели вполне подойдут для нового кода, НО:

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

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

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

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

Проверьте переговоры здесь: http://channel9.msdn.com/Events/GoingNative/2013 (особенно доклад Страуструпа).

Краткий ответ - нет, при условии, что "современный C++" ->= C++11

Длинный ответ заключается в том, что это не всегда так, и попытка реструктурировать большой проект почти всегда трудна. То, как мы думаем о проблемах, ограничено инструментами, которые мы должны решать. Есть много случаев, когда такой рефакторинг выполняется, когда просто имеет больше смысла использовать указатели, чем пытаться повторно выразить базовую логику, чтобы быть удобными для классов и интеллектуальных указателей. Я думаю, что это не тот случай, когда умные указатели используются слишком часто, и больше случай, когда классы используются недостаточно. YMMV;-)

Другие вопросы по тегам