Почему библиотеки и фреймворки C++ никогда не используют интеллектуальные указатели?



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



однако я заметил, что такие фреймворки, как Qt, wxWidgets и библиотеки, такие как Boost, никогда не возвращаются и не ожидают интеллектуальных указателей, как будто они их вообще не используют. Вместо этого они возвращают или ожидают необработанные указатели. Есть ли для этого какая-то причина? Должен ли я держаться подальше от умных указателей, когда я пишу публику API и почему?



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

636   8  

8 ответов:

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

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

но из-за отсутствия стандартного ABI, вы вообще не может безопасно передавайте эти объекты через границы модуля. В ССЗ shared_ptr вероятно, отличается от MSVC shared_ptr, который тоже может отличаться от Intel shared_ptr. Даже с то же самое компилятор, эти классы не гарантируют двоичную совместимость между версиями.

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

ситуация не так хороша для C++. Отдельные компиляторы могут обрабатывать взаимодействие между своими двоичными файлами, поэтому у вас есть возможность распространять версию для каждого поддерживаемого компилятора, часто GCC и MSVC. Но в свете этого большинство библиотек просто экспортируют интерфейс C-и это означает необработанные указатели.

не библиотечный код должен, однако, как правило, предпочитают смарт-указатели над raw.

там может быть много причин. Перечислить несколько из них:

  1. умные указатели стали частью стандарта совсем недавно. До тех пор они входили в состав других библиотек
  2. их основное использование-избежать утечек памяти; многие библиотеки не имеют собственного управления памятью; как правило, они обеспечивают утилиты и API
  3. они реализованы как обертка, так как они на самом деле являются объектами, а не указателями. Который имеет дополнительную стоимость времени / пространства, по сравнению с сырые указатели; пользователи библиотек могут не захотеть иметь такие издержки

Edit: использование интеллектуальных указателей-это полностью выбор разработчика. Это зависит от различных факторов.

  1. в системах с критической производительностью вы можете не использовать smart указатели, которые генерируют накладные расходы

  2. проект, который нуждается в обратной совместимости, вы не хотите чтобы использовать смарт-указатели, которые имеют C++11 особенности

Edit2 есть строка из нескольких downvotes в промежутке 24 часов из-за ниже прохода. Я не понимаю, почему ответ понижен, хотя ниже приведено только дополнительное предложение, а не ответ.
Однако, в C++ всегда облегчает вам выбор. :) например,

template<typename T>
struct Pointer {
#ifdef <Cpp11>
  typedef std::unique_ptr<T> type;
#else
  typedef T* type;
#endif
};

и в коде использовать его как:

Pointer<int>::type p;

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

например, T* должен быть удален явно умный указатель не. Мы можем иметь шаблонный Destroy() чтобы справиться с этим.

template<typename T>
void Destroy (T* p)
{
  delete p;
}
template<typename T>
void Destroy (std::unique_ptr<T> p)
{
  // do nothing
}

и использовать его как:

Destroy(p);

таким же образом, для необработанного указателя мы можем скопировать его непосредственно и умный указатель мы можем использовать специальную операцию.

Pointer<X>::type p = new X;
Pointer<X>::type p2(Assign(p));

здесь Assign() в:

template<typename T>
T* Assign (T *p)
{
  return p;
}
template<typename T>
... Assign (SmartPointer<T> &p)
{
  // use move sematics or whateve appropriate
}

есть две проблемы с интеллектуальными указателями (до C++11):

  • нестандартные, поэтому каждая библиотека имеет тенденцию изобретать свои собственные (NIH syndrom & dependencies issues)
  • потенциальной стоимостью

The по умолчанию умный указатель, в том, что это бесплатно, является unique_ptr. К сожалению, для этого требуется семантика перемещения C++11, которая появилась только недавно. Все остальные умные указатели имеют стоимость (shared_ptr,intrusive_ptr) или имеют менее идеальную семантику (auto_ptr).

С C++11 за углом, в результате std::unique_ptr, хотелось бы думать, что это, наконец, закончилось... Я не так оптимистичен.

только несколько основных компиляторов реализуют большую часть C++11, и только в их последних версиях. Мы можем ожидать, что крупные библиотеки, такие как QT и Boost, будут готовы сохранить совместимость с C++03 на некоторое время, что несколько исключает широкое внедрение новых и блестящих интеллектуальных указателей.

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

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

Я мог бы взять в качестве примера библиотеку, над которой мы работали, где после нескольких месяцев разработки я понял, что мы использовали только указатели и умные указатели в нескольких классах (3-5% всех классов).

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

Edit (Я не могу комментировать из-за моей репутации): передача переменных по ссылке очень гибкая: если вы хотите объект чтобы быть только для чтения, вы можете использовать ссылку const (вы все еще можете делать некоторые неприятные броски, чтобы иметь возможность писать объект), но вы получаете максимальную возможную защиту (то же самое с интеллектуальными указателями). Но я согласен, что гораздо приятнее просто вернуть объект.

Qt бессмысленно заново изобрел многие части стандартной библиотеки в попытке стать Java. Я считаю, что у него действительно есть свои умные указатели сейчас, но в целом, это вряд ли вершина дизайна. wxWidgets, насколько мне известно, был разработан задолго до того, как были написаны полезные интеллектуальные указатели.

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

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

хороший вопрос. Я не знаю конкретных статей, на которые вы ссылаетесь, но я читал подобные вещи время от времени. Я подозреваю, что авторы таких статей склонны питать предубеждение против программирования в стиле C++. Если писатель программирует на C++ только тогда, когда он должен, а затем возвращается к Java или таким, как только он может, то он действительно не разделяет мышление C++.

можно подозревать, что некоторые или большинство тех же авторов предпочитают сборщик мусора менеджеры памяти. Я нет, но я думаю иначе, чем они.

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

одна из отличных вещей в C++ - это поддержка программирования встроенных систем. Использование голых указателей является частью об этом.

обновление: комментатор правильно заметил, что c++'s new unique_ptr (доступно с TR1) не учитывает ссылки. У комментатора также есть другое определение "умного указателя", чем я имею в виду. Возможно, он прав насчет определения.

уточнения: поток комментариев ниже освещает. Все это рекомендуется читать.

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

люди могут иметь все виды различных требований к управлению памятью и решений за пределами интеллектуальных указателей. Я мог бы сам управлять памятью, я мог бы выделять пространство для вещей в пуле памяти, поэтому он выделяется заранее, а не во время выполнения (полезно для игр). Возможно, я использую собранную реализацию мусора C++ (C++11 делает это возможным, хотя еще не существует). Или, может быть, я просто не делаю ничего продвинутого достаточно беспокоиться о том, чтобы возиться с ними, я могу знать, что я не собираюсь забывать неинициализированные объекты и так далее. Может быть, я просто уверен в своей способности управлять памятью без указательного костыля.

интеграция с C-это тоже другой вопрос.

еще одна проблема-умные указатели являются частью STL. C++ предназначен для использования без STL.

Это также зависит от того, в каком домене вы работаете. Я пишу игровые движки для жизни, мы избегаем повышения, как чумы, в играх накладные расходы на повышение неприемлемы. В нашем основном движке мы закончили тем, что написали свою собственную версию stl (так же, как и ea stl).

Если бы я должен был написать приложение forms, я мог бы рассмотреть возможность использования интеллектуальных указателей; но как только управление памятью становится второй натурой, не имеющей гранулярного контроля над памятью, становится тихим раздражающим.

Comments

    Ничего не найдено.