Использование интеллектуальных указателей в качестве стандарта программирования?
все больше и больше я слышу, что я должен использовать умные указатели вместо голых указателей, несмотря на то, что у меня реализована эффективная система утечки памяти.
Что такое правильный подход к программированию при использовании смарт-указателей, пожалуйста? Должны ли они действительно использоваться, даже если я проверяю утечки памяти на выделенных блоках памяти? Это все еще зависит от меня? Если я не использую их, можно ли считать это слабостью программирования?
Если умные указатели(ex: std:: auto_ptr) настоятельно рекомендуется, я должен использовать их вместо голого указателя?
9 ответов
вы должны использовать RAII для обработки всех распределений ресурсов.
умные указатели-это только один общий частный случай этого правила.
и умные указатели больше, чем просто shared_ptr
. Существуют разные интеллектуальные указатели с разной семантикой владения. Используйте тот, который соответствует вашим потребностям. (Основные из них scoped_ptr
, shared_ptr
, weak_ptr
и auto_ptr
/unique_ptr
(предпочитайте последнее, где это возможно). В зависимости от компилятора они могут быть доступны в стандартной библиотеке, как часть TR1, или не совсем, в этом случае вы можете получить их через библиотеки Boost.
и да, вы должны использовать эти. Это ничего не стоит (если все сделано правильно, вы потеряете нулевую производительность), и это принесет вам много пользы (память и другие ресурсы автоматически освобождаются, и вам не нужно помнить, чтобы обрабатывать его вручную, и ваш код с помощью ресурса становится короче и лаконичнее)
обратите внимание, что не каждое использование указателя представляет какой-то ресурс владение, и поэтому не все использование необработанного указателя неверно. Если вам просто нужно указать на объект, принадлежащий кому-то другому, необработанный указатель идеально подходит. Но если ... --15-->вы владеть объектом, то вы должны взять на себя надлежащее владение им, либо давая самому классу семантику RAII, либо обернув его в умный указатель.
вы не можете просто слепо заменить std::auto_ptr
для каждого необработанного указателя. В частности, auto_ptr
передает право собственности на уступку, что отлично подходит для некоторых целей, но определенно не для других.
существует реальная причина, по которой существует несколько разновидностей интеллектуальных указателей (например, shared_ptr, weak_ptr, auto_ptr/unique_ptr и т. д. Каждый выполняет свою цель. Одна из главных слабостей" сырого " указателя заключается в том, что он имеет так много различных применений (и имеет эту универсальность в основном потому, что он мало или ничего, чтобы помочь в какой-либо одной цели). Умные указатели, как правило, более специализированы, что означает, что они могут быть более умными в выполнении одной вещи хорошо, но также означает, что вы должны выбрать правильный для работы, или это в конечном итоге Донг неправильные вещи полностью.
интеллектуальные указатели позволяют автоматически определять время жизни объектов, на которые он ссылается. это главное понять.
и нет, вы не должны использовать смарт-указатели везде, только если вы хотите автоматизировать время жизни ваших объектов вместо того, чтобы иметь, например, объект, управляющий этими объектами внутри от рождения до смерти. Это как любой инструмент: он решает определенные проблемы, а не все проблемы.
для каждого объекта, вы следует подумать о жизненном цикле, который он пройдет, а затем выбрать одно из простейших правильных и эффективных решений. Иногда это будет shared_ptr, потому что вы хотите, чтобы объект использовался несколькими компонентами и автоматически уничтожался после того, как он больше не используется. Иногда вам нужен объект только в текущей области / Родительском объекте, поэтому scoped_ptr может быть более подходящим. Иногда вам нужен только один владелец экземпляра, поэтому unique_ptr подходит. Может быть, вы найдете случаи, когда вы знайте алгоритм, который может определять / автоматизировать время жизни объекта, поэтому вы напишете для него свой собственный интеллектуальный указатель.
например, в противоположном случае использование пулов запрещает использовать smart_ptr. Голые указатели могут быть более желанным простым и эффективным решением в этом конкретном (но распространенном во встроенном программном обеспечении) случае.
см. этот ответ (от меня) для получения дополнительных объяснений : https://softwareengineering.stackexchange.com/questions/57581/in-c-is-it-a-reflection-of-poor-software-design-if-objects-are-deleted-manuall/57611#57611
должны ли они действительно использоваться, даже если я проверяю утечки памяти на выделенных блоках памяти?
Да
Вся цель смарт-указателей, это поможет вам реализовать RAII (SBRM), что в основном позволяет самому ресурсу взять на себя ответственность за его освобождение, и ресурс не должен явно полагаться на вас помнить чтобы освободить его.
Если я не использую их, можно ли считать это слабостью программирования?
нет,
Это не слабость, а неудобство или ненужные хлопоты, чтобы явно управлять ресурсами самостоятельно, если вы не используете смарт-указатели(RAII). Цель интеллектуальных указателей для реализации RAII-обеспечить эффективный и беспроблемный способ обработка ресурсов, и вы просто не будете использовать его, если вы его не используете. Настоятельно рекомендуется использовать его исключительно для многочисленные преимущества он обеспечивает.
Если умные указатели(ex: std::auto_ptr)настоятельно рекомендуется, должен ли я использовать их вместо каждого голого указателя?
Да
Вы должны использовать смарт-указатели везде, где это возможно потому что просто нет недостатка в их использовании и просто многочисленные преимущества для их использования.
Не используйте auto_ptr
хотя, потому что он уже устарел!! Существуют различные другие умные указатели, которые можно использовать в зависимости от требований. Вы можете обратиться по ссылке выше, чтобы узнать больше о них.
это хитрый вопрос, и тот факт, что в настоящее время режим использование смарт-указателей везде не делает вещи проще. Умный указатели могут помочь в определенных ситуациях, но вы, конечно, не могу просто используйте их везде, не думая. Существует много различных типов умных указателей, и вы должны думать о том, какой из них подходит в каждом случае; и даже тогда большинство ваших указателей (по крайней мере, в типичном приложения в доменах, в которых я работал) должны быть raw указатели.
независимо от подхода, несколько пунктов стоит упомянуть:
Не используйте динамическое распределение, если вам не нужно. Во многом приложения,только вещи, которые должны быть динамически выделяемой являются объектами с определенным временем жизни, определяемым приложением логика. Не используйте динамическое распределение для объектов с семантикой значений.
что касается объекта сущности, те, которые моделируют что-то в домен приложения: они должны быть созданы и уничтожены по к логике программы. Независимо от того, есть ли указатели они или нет. Если их уничтожение вызывает проблему, то у вас есть ошибка в логике вашей программы где-то (не обработка события правильно, так далее.), и использование смарт-указателей ничего не изменит.
типичным примером объекта сущности может быть клиентское соединение в
сервер создается, когда клиент соединяется и разрушается, когда
клиент отключается. Во многих таких случаях наиболее целесообразным является управление
будет delete this
, Так как это соединение, которое получит
событие разъединения. (Объекты, которые содержат указатели на такой объект
придется зарегистрироваться, чтобы быть в курсе его
разрушение. Но такие указатели предназначены исключительно для навигации и не должны
будьте умными указателями.)
что вы обычно найдете, когда люди пытаются использовать смарт-указатели
повсюду is что утечки памяти; типичные счетчики ссылки не делают
циклы ручки, и конечно, типичные применения полны циклов: a
Connection
до Client
, который подключен к его, и
the Client
будет содержать список Connection
где это связано.
И если умный указатель boost::shared_ptr
, там также определенное
риск болтающихся указателей: это далеко не легко создать два
boost::shared_ptr
по тому же адресу (что приводит к двум счетчикам
для обращения.)
если настоятельно рекомендуется использовать интеллектуальные указатели(например: std::auto_ptr), следует ли использовать их вместо каждого голого указателя?
по-моему, да, вы должны это для каждый указатель, который у вас есть.
вот мои идеи по управлению ресурсами на C++ (не стесняйтесь не соглашаться):
- хорошее управление ресурсами требует мышления с точки зрения собственности.
- ресурсы должны управляться объекты (RAII).
- обычно одиночное владение предпочтительнее совместного владения.
- в идеале создатель также является владельцем объекта. (Однако существуют ситуации, когда передача права собственности осуществляется в порядке.)
это приводит к следующим практикам:
сделать
boost::scoped_ptr
выбор по умолчанию для локальных переменных и переменных-членов. Имейте в виду, что с помощьюscoped_ptr
переменные-члены класса некопируемых. Если вы не хотите этого, смотрите следующий пункт.-
использовать
boost::shared_ptr
для контейнеров или для включения долевой собственности:// Container of MyClass* pointers:
typedef boost::shared_ptr<MyClass> MyClassPtr;
std::vector<MyClassPtr> vec;
-
на
std::auto_ptr
(C++03) может использоваться для передачи прав собственности. Например, как возвращаемое значение factory или clone методы:// Factory method returns auto_ptr
std::auto_ptr<Button> button = Button::Create(...);
// Clone method returns auto_ptr
std::auto_ptr<MyClass> copy = obj->clone();
// Use release() to transfer the ownership to a scoped_ptr or shared_ptr
boost::scoped_ptr<MyClass> copy(obj->clone().release());
-
Если вам нужно сохранить указатель, который у вас нет, вы можете использовать необработанный указатель:
this->parent = inParentObject;
в некоторых ситуациях a
boost::weak_pointer
не требуется. Вижу документация для получения дополнительной информации.
В общем, вы должны предпочесть умные указатели, но есть несколько исключений.
Если вам нужно изменить указатель, например, чтобы предоставить const
версия, которая становится почти невозможной с помощью смарт-указателей.
интеллектуальные указатели используются для управления временем жизни объекта. Часто, когда вы передаете указатель на функцию, функция не влияет на время жизни; функция не пытается удалить объект и не хранит копию указателя. Этот вызывающий код не может удалить объект, пока функция не вернется. В этом случае вполне приемлема тупая указка.
да. Предполагая, что у вас есть C++0x, используйте unique_ptr
или shared_ptr
(по мере необходимости), чтобы обернуть все необработанные указатели вы new
вверх. С помощью make_shared
, shared_ptr
это очень мощно. Если вам не нужен подсчет ссылок, то unique_ptr
поможет вам лучше perf. Оба они ведут себя правильно в коллекциях и других обстоятельствах, где auto_ptr
тупой указатель.
использование интеллектуальных указателей (shared_ptr или иначе) везде-плохая идея. Хорошо использовать shared_ptr для управления временем жизни объектов / ресурсов, но не рекомендуется передавать их в качестве параметров функциям и т. д. Это увеличивает вероятность круговых ссылок и других чрезвычайно трудных для отслеживания ошибок (личный опыт: попробуйте выяснить, кто не должен удерживать ресурс в 2 миллионах строк кода, если каждый вызов функции изменяет счетчик ссылок - вы закончите вверх, думая, что ребята, которые делают такие вещи, - это m***ns). Лучше передать необработанный указатель или ссылку. Ситуация еще хуже в сочетании с "ленивое" создание экземпляра. Я бы предложил разработчикам знать жизненный цикл объектов, которые они пишут и используют shared_ptr для управления этим (RAII), но не расширять использование shared_ptr за его пределами.