Какой указатель я использую, когда?
хорошо, так что в последний раз, когда я писал C++ для жизни,std::auto_ptr все СТД Либ был доступен, и boost::shared_ptr был весь гнев. Я никогда не заглядывал в другие типы интеллектуальных указателей, предоставляемые boost. Я понимаю, что C++11 теперь предоставляет некоторые из типов boost, но не все из них.
Итак, у кого-то есть простой алгоритм, чтобы определить, когда использовать какой умный указатель? Предпочтительно включая советы относительно тупых указателей (необработанные указатели, такие как T*) и остальные интеллектуальные указатели boost. (Что-то вроде этого было бы здорово).
4 ответов:
долевой собственности:
Элементshared_ptrиweak_ptrпринятый стандарт в значительной степени совпадает с их увеличить коллегами. Используйте их, когда вам нужно поделиться ресурсом и не знаете, какой из них будет последним, чтобы быть живым. Используйтеweak_ptrнаблюдать за общим ресурсом, не влияя на его срок службы, не нарушать циклы. Циклы сshared_ptrобычно не должно происходить-два ресурса не могут владеть друг другом.обратите внимание, что повысить дополнительно предлагает
shared_array, что может быть подходящей альтернативой дляshared_ptr<std::vector<T> const>.далее, повышение предложения
intrusive_ptr, которые являются легким решением, если ваш ресурс уже предлагает управление с учетом ссылок, и вы хотите принять его в принцип RAII. Этот стандарт не был принят.уникальная собственности:
Повышение также имеетscoped_ptr, который не копируется и для которого вы не могу указать делетер.std::unique_ptrиboost::scoped_ptrна стероидах и должно быть вашим выбор по умолчанию, если вам нужен умный указатель. Это позволяет указать делетер в его аргументах шаблона и является движимое в отличие отboost::scoped_ptr. Он также полностью используется в контейнерах STL, если вы не используете операции, которые нуждаются в копируемых типах (очевидно).еще раз обратите внимание, что Boost имеет версию массива:
scoped_array, который стандарт унифицировал мимо требуяstd::unique_ptr<T[]>частичная специализация, которая будетdelete[]указатель вместоdeleteing его (сdefault_deleter).std::unique_ptr<T[]>предлагаетoperator[]вместоoperator*иoperator->.обратите внимание, что
std::auto_ptrвсе еще в стандарте, но это устаревший.§D.10 [depr.auto.ptr]шаблон класс
auto_ptrустарела. [ Примечание: шаблон классunique_ptr(20.7.1) обеспечивает лучшее решение. -конец Примечание]нет собственности:
Используйте тупые указатели (необработанные указатели) или ссылки для не владеющие ссылки ресурсы, и когда вы знаете, что ресурс переживет объект / область ссылки. Предпочитайте ссылки и используйте необработанные указатели, когда вам нужна либо возможность обнуления, либо перенастройка.если вы хотите не владеющий ссылкой на ресурс, но вы не знаете, если ресурс переживет объект, который ссылается на него, упакуйте ресурс в
shared_ptrи использоватьweak_ptr- вы можете проверить, если родительshared_ptrживет сlock, который вернет ashared_ptrэто ненулевое значение, если ресурс все еще существует. Если вы хотите проверить, мертв ли ресурс, используйтеexpired. Эти два могут звучать похоже, но очень разные перед лицом параллельного выполнения, какexpiredтолько гарантирует его возвращаемое значение для этого одного оператора. Казалось бы, невинный тест какif(!wptr.expired()) something_assuming_the_resource_is_still_alive();- это потенциальное состояние гонки.
решение о том, какой умный указатель использовать, - это вопрос собственности. Когда дело доходит до управления ресурсами, объекта принадлежит объект B, если он управляет временем жизни объекта B. например, переменные-члены принадлежат соответствующим объектам, поскольку время жизни переменных-членов связано с временем жизни объекта. Вы выбираете интеллектуальные указатели на основе того, как объект принадлежит.
обратите внимание, что владение в программной системе является отдельно от собственности, как мы думаем об этом за пределами программного обеспечения. Например, человек может "владеть" своим домом, но это не обязательно означает, что
Personобъект имеет контроль над временем жизни aHouse"объект". Объединение этих концепций реального мира с концепциями программного обеспечения-это верный способ запрограммировать себя в дыру.
если у вас есть единоличное право собственности на объект, использовать
std::unique_ptr<T>.если у вас есть общее право собственности на объект...
- Если нет циклов в собственности, используйтеstd::shared_ptr<T>.
- Если есть циклы, определите "направление" и используйтеstd::shared_ptr<T>в одну сторону иstd::weak_ptr<T>в другой.если объект принадлежит вам, но есть потенциал отсутствия владельца, используйте обычные указатели
T*(например, материнская указатели).если объект принадлежит вам (или иным образом имеет гарантированное существование), Используйте ссылки
T&.
предостережение: будьте в курсе стоимости смарт-указателей. В память или производительность ограниченные среды, это может быть полезно просто использовать обычные указатели с более ручной схемой для управления памятью.
затраты:
- если у вас есть пользовательский делетер (например, вы используете пулы распределения), то это приведет к накладным расходам на указатель, которые можно легко избежать путем ручного удаления.
std::shared_ptrимеет накладные расходы на увеличение количества ссылок при копировании, а также уменьшение при уничтожении с последующей проверкой 0-count с удалением удерживаемого объекта. В зависимости от реализации это может привести к раздуванию кода и вызвать проблемы с производительностью.- время компиляции. Как и во всех шаблонах, интеллектуальные указатели негативно влияют на время компиляции.
примеры:
struct BinaryTree { Tree* m_parent; std::unique_ptr<BinaryTree> m_children[2]; // or use std::array... };двоичное дерево не имеет своего родителя, но существование дерева подразумевает существование его родителя (или
nullptrдля root), так что использует обычный указатель. Двоичное дерево (со значением семантика) имеет единоличную собственность на своих детей, так что этоstd::unique_ptr.struct ListNode { std::shared_ptr<ListNode> m_next; std::weak_ptr<ListNode> m_prev; };здесь узел списка владеет своим следующим и предыдущим списками, поэтому мы определяем направление и используем
shared_ptrна следующий иweak_ptrдля prev, чтобы разорвать цикл.
использовать
unique_ptr<T>все время, кроме тех случаев, когда вам нужен подсчет ссылок, в этом случае используйтеshared_ptr<T>(и в очень редких случаях,weak_ptr<T>для предотвращения опорных циклов). Почти в каждом случае передача уникального владения просто прекрасна.Raw указатели: хорошо, только если вам нужны ковариантные возвраты, не владеющие указаниями, которые могут произойти. В противном случае они не очень полезны.
массив указателей:
unique_ptrимеет специализацию дляT[]что автоматически вызываетdelete[]на результат, так что вы можете смело делатьunique_ptr<int[]> p(new int[42]);например.shared_ptrвам все равно понадобится пользовательский удалитель, но вам не понадобится специализированный общий или уникальный указатель массива. Конечно, такие вещи обычно лучше всего заменить наstd::vectorв любом случае. К сожалениюshared_ptrне обеспечивает функцию доступа к массиву, поэтому вам все равно придется вручную вызватьget(), аunique_ptr<T[]>предоставляетoperator[]вместоoperator*иoperator->. В любом случае, вы должны сами себя проверить. Это делаетshared_ptrнемного менее удобный, хотя, возможно, общее преимущество и отсутствие зависимости от повышения делаетunique_ptrиshared_ptrснова победители.указатели с областью действия: сделаны неуместными
unique_ptr, так какauto_ptr.там действительно больше ничего нет. В C++03 без семантики перемещения эта ситуация была очень сложной, но в C++11 совет очень прост.
есть еще использует для других интеллектуальных указателей, как
intrusive_ptrилиinterprocess_ptr. Однако, они же очень ниша и совершенно ненужная в общем случае.
случаи, когда использовать
unique_ptr:
- методы фабрики
- члены, которые являются указателями (pimpl включены)
- хранение указателей в контейнерах stl (чтобы избежать перемещений)
- использование больших локальных динамических объектов
случаи, когда использовать
shared_ptr:
- совместное использование объектов в потоках
- общий доступ к объектам в целом
случаи, когда использовать
weak_ptr:
- большая карта, которая действует как общая ссылка (ex. карта всех открытых сокетов)
не стесняйтесь редактировать и добавлять больше
Comments