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

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

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

Если умные указатели(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++ (не стесняйтесь не соглашаться):

  1. хорошее управление ресурсами требует мышления с точки зрения собственности.
  2. ресурсы должны управляться объекты (RAII).
  3. обычно одиночное владение предпочтительнее совместного владения.
  4. в идеале создатель также является владельцем объекта. (Однако существуют ситуации, когда передача права собственности осуществляется в порядке.)


это приводит к следующим практикам:

  1. сделать boost::scoped_ptr выбор по умолчанию для локальных переменных и переменных-членов. Имейте в виду, что с помощью scoped_ptr переменные-члены класса некопируемых. Если вы не хотите этого, смотрите следующий пункт.

  2. использовать boost::shared_ptr для контейнеров или для включения долевой собственности:

    // Container of MyClass* pointers:
    typedef boost::shared_ptr<MyClass> MyClassPtr;
    std::vector<MyClassPtr> vec;

  3. на 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());

  4. Если вам нужно сохранить указатель, который у вас нет, вы можете использовать необработанный указатель:

    this->parent = inParentObject;

  5. в некоторых ситуациях 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 за его пределами.