Использование интеллектуальных указателей в качестве стандарта программирования?
Все больше и больше я слышу, что я должен использовать умные указатели вместо голой указатели, несмотря на то, что у меня есть эффективная система утечки памяти.
Что такое правильный подход к программированию при использовании интеллектуальных указателей, пожалуйста? Должны ли они действительно использоваться, даже если я проверю утечки памяти на выделенные блоки памяти? Это все еще для меня? Если я их не использую, можно ли это считать слабостью программирования?
Если настоятельно рекомендуется использовать интеллектуальные указатели (ex: std:: auto_ptr), следует ли использовать их вместо каждого открытого указателя?
Ответы
Ответ 1
Вы должны использовать RAII для обработки всех распределений ресурсов.
Умные указатели - всего лишь один общий частный случай этого правила.
И интеллектуальные указатели больше, чем просто shared_ptr
. Существуют разные интеллектуальные указатели с разной степенью принадлежности. Используйте тот, который соответствует вашим потребностям. (Основными являются scoped_ptr
, shared_ptr
, weak_ptr
и auto_ptr
/unique_ptr
(предпочитайте последний, если он доступен). В зависимости от вашего компилятора они могут быть доступны в стандартной библиотеке как часть TR1, или вообще нет, и в этом случае вы можете получить их через библиотеки Boost.
И да, вы должны абсолютно их использовать. Это ничего не стоит (если все сделано правильно, вы теряете нулевую производительность), и он набирает вас много (память и другие ресурсы автоматически освобождаются, и вам не нужно забывать обрабатывать их вручную, а ваш код с использованием ресурса получает короче и более кратким)
Обратите внимание, что не все использование указателя представляет собой своеобразное владение ресурсами, и поэтому не все использование raw-указателя неверно. Если вам просто нужно указать объект, принадлежащий кому-то другому, необработанный указатель идеально подходит. Но если вы являетесь владельцем объекта, тогда вы должны взять на себя надлежащее владение им, либо предоставив семантику класса RAII, либо путем ее включения в интеллектуальный указатель.
Ответ 2
Вы не можете просто слепо заменить std::auto_ptr
на каждый необработанный указатель. В частности, auto_ptr
передает право собственности на присвоение, что отлично подходит для некоторых целей, но определенно не для других.
Существует настоящая причина наличия нескольких разновидностей интеллектуальных указателей (например, shared_ptr, weak_ptr, auto_ptr/unique_ptr и т.д.). Каждый из них выполняет другую цель. Одной из основных недостатков "необработанного" указателя является то, что у него так много разных применений (и эта универсальность во многом обусловлена тем, что он мало или совсем не помогает в какой-либо одной цели). Умные указатели имеют тенденцию быть более специализированными, а это значит, что они могут быть более умными в том, чтобы делать что-то одно, но также означает, что вам нужно выбрать правильный вариант для работы, иначе он полностью закончит неправильные вещи.
Ответ 3
Должны ли они действительно использоваться, даже если я проверю утечки памяти на выделенные блоки памяти?
Да
Вся цель умных указателей заключается в том, что она помогает вам реализовать RAII (SBRM), что в основном позволяет самому ресурсу взять на себя ответственность за его освобождение и ресурс не должен полагаться на вас явно запомнить, чтобы освободить его.
Если я их не использую, можно ли это считать слабостью программирования?
NO
Это не слабость, а неудобство или излишняя хлопот явным образом управлять ресурсами самостоятельно, если вы не используете Smart-указатели (RAII). Цель интеллектуальных указателей для реализации RAII - обеспечить эффективный и удобный способ обработки ресурсов, и вы просто не воспользуетесь им, если вы его не используете. Настоятельно рекомендуется использовать его исключительно для многочисленных преимуществ, которые он предоставляет.
Если настоятельно рекомендуется использовать умные указатели (ex: std:: auto_ptr) , следует ли использовать их вместо каждого открытого указателя?
Да
Вы должны использовать интеллектуальные указатели, где это возможно, потому что просто нет недостатка в их использовании и просто многочисленных преимуществ для их использования.
Не используйте auto_ptr
, хотя, потому что он уже устарел!! Существуют различные другие интеллектуальные указатели, которые вы можете использовать в зависимости от требования. Вы можете ссылаться на ссылку выше, чтобы узнать больше о них.
Ответ 4
Умные указатели позволяют автоматически определять срок жизни объектов, на которые он ссылается. Это главное, чтобы понять.
Итак, нет, вы не должны использовать интеллектуальные указатели везде, только если вы хотите автоматизировать время жизни ваших объектов, вместо того, чтобы иметь, например, объект, управляющий этими объектами внутри от рождения до смерти. Это похоже на любой инструмент: он решает конкретные проблемы, а не все проблемы.
Для каждого объекта вы должны подумать о жизненном цикле, в котором он пройдет, затем выберите одно из самых простых правильных и эффективных решений. Иногда это будет 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
Ответ 5
Если настоятельно рекомендуется использовать интеллектуальные указатели (ex: std:: auto_ptr), я должен использовать их вместо каждого открытого указателя?
По-моему, да, вы должны это сделать для каждого указателя, который у вас есть.
Вот мои идеи по управлению ресурсами в С++ (не стесняйтесь не соглашаться):
- Хорошее управление ресурсами требует мышления с точки зрения собственности.
- Управление ресурсами должно осуществляться с помощью объектов (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
(С++ 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
. Дополнительную информацию см. В документации.
Ответ 6
Это сложный вопрос, и тот факт, что в настоящее время существует режим
использование интеллектуальных указателей во всем мире не упрощает работу. Умная
указатели могут помочь в определенных ситуациях, но вы, конечно, не можете просто
использовать их везде, не задумываясь. Существует много разных типов
умных указателей, и вам нужно подумать о том, какой из них подходит
в каждом случае; и даже тогда большинство ваших указателей (по крайней мере, в типичных
приложения в доменах, в которых я работал) должны быть грубыми указателями.
Независимо от подхода, стоит упомянуть несколько пунктов:
-
Не используйте динамическое выделение, если вам не нужно. Во многих
приложений, единственное, что нужно динамически распределять
являются объектами с определенным временем жизни, определяемыми приложением
логика. Не используйте динамическое распределение для объектов с семантикой значений.
-
Что касается объекта сущности, те, которые моделируют что-то в
домен приложения: они должны быть созданы и уничтожены в соответствии с
к логике программы. Независимо от того, существуют ли указатели на
их или нет. Если их разрушение вызывает проблему, то у вас есть
ошибка в вашей программной логике где-то (не правильно обрабатывать событие,
и т.д.), а использование интеллектуальных указателей ничего не изменит.
Типичным примером объекта-объекта может быть клиентское соединение в
сервер, создается при подключении клиента и разрушается, когда
клиент отключается. Во многих случаях наиболее подходящее управление
будет delete this
, так как это соединение, которое будет получать
событие разъединения. (Объекты, которые содержат указатели на такой объект
должен будет зарегистрироваться у него, чтобы получить информацию о его
разрушение. Но такие указатели предназначены исключительно для навигации, и не должны
быть умными указателями.)
Что вы обычно найдете, когда люди пытаются использовать интеллектуальные указатели
повсюду происходит утечка памяти; типичные контрольные счетчики не
и, конечно, типичные приложения полны циклов: a
Connection
будет указывать на Client
, который с ней связан, и
Client
будет содержать список Connection
, где он подключен.
И если умный указатель boost::shared_ptr
, там также определенная
риск оборванных указателей: он легко может создать два
boost::shared_ptr
к тому же адресу (что приводит к двум счетчикам
для ссылок).
Ответ 7
Да. Предполагая, что у вас есть С++ 0x, используйте unique_ptr
или shared_ptr
(в зависимости от ситуации), чтобы обернуть все исходные указатели, которые вы new
вверх. С помощью make_shared
, shared_ptr
является высокоэффективным. Если вам не нужен подсчет ссылок, тогда unique_ptr
улучшит ваш функционал. Оба они ведут себя правильно в коллекциях и других обстоятельствах, где auto_ptr
был немым указателем.
Ответ 8
В общем вы должны предпочесть интеллектуальные указатели, но есть несколько исключений.
Если вам нужно переписать указатель, например, чтобы предоставить версию const
, что становится почти невозможным с помощью интеллектуальных указателей.
Умные указатели используются для управления временем жизни объекта. Часто, когда вы передаете указатель на функцию, функция не влияет на время жизни; функция не пытается удалить объект и не сохраняет копию указателя. Вызывающий код не может удалить объект до тех пор, пока функция не вернется. В этом случае немой указатель вполне приемлем.
Ответ 9
Использование интеллектуальных указателей (shared_ptr или иначе) ВЕСЬ - плохая идея. Хорошо использовать shared_ptr для управления временем жизни объектов/ресурсов, но не рекомендуется передавать их в качестве параметров функций и т.д. Это увеличивает вероятность циклических ссылок и других чрезвычайно трудно отслеживать ошибки (личный опыт: попытайтесь выяснить, кто не должен удерживаться на ресурсе в 2 миллионах строк кода, если каждый вызов функции изменяет счет ссылки - вы в конечном итоге думаете, что ребята, которые делают такие вещи, являются m *** ns). Лучше передать необработанный указатель или ссылку.
Ситуация еще хуже, когда она сочетается с ленивым экземпляром.
Я бы предположил, что разработчики должны знать жизненный цикл объектов, которые они пишут, и использовать shared_ptr для управления этим (RAII), но не расширять использование shared_ptr за пределами этого.