Я широко использую shared_ptr и STL в проекте, и это приводит к слишком длинным, подверженным ошибкам типам, таким как shared_ptr > (я по предпочтению программист ObjC, где длинные имена норма, и все же это слишком много. Я думаю, было бы гораздо понятнее последовательно вызывать этот FooListPtr и документировать соглашение об именах, что «Ptr» означает shared_ptr, а «List» означает вектор shared_ptr.
для начала, я рекомендую использовать хорошие структуры дизайна для определения области видимости (например, пространства имен), а также описательные, не сокращенные имена для typedefs. FooListPtr
ужасно короткий, имо. никто не хочет догадываться, что означает сокращение (или удивляться, обнаружив, что Foo является const, shared и т. д.), и никто не хочет изменять свой код просто из-за коллизий в области видимости.
это также может помочь выбрать префикс для typedefs в ваших библиотеках (а также других распространенных категориях).
также плохая идея вытаскивать типы из заявленной области видимости:
namespace MON {
namespace Diddy {
class Foo;
} /* << Diddy */
/*...*/
typedef Diddy::Foo Diddy_Foo;
} /* << MON */
Есть исключения из этого:
- полностью закрытый тип
- отдельный тип в новой области видимости
в то время как мы находимся, using
в областях пространства имен и псевдонимах пространства имен следует избегать - уточните область, если вы хотите минимизировать обслуживание в будущем.
Это легко определить, но это вызывает головные боли с заголовками. Кажется, у меня есть несколько вариантов определения FooListPtr:
foo.h. Это переплетает все заголовки и создает серьезные проблемы со сборкой, так что это не стартер.
это может быть вариант для объявлений, которые действительно зависят от других объявлений. Это означает, что вам нужно разделить пакеты или существует общий локализованный интерфейс для подсистем.
FooFwd.h («прямой заголовок»). Это то, что предлагает Effective C ++ на основе iosfwd.h. Это очень непротиворечиво, но затраты на поддержание удвоенного количества заголовков в лучшем случае раздражают.
не беспокойся о поддержании этого, правда. это хорошая практика. компилятор использует предварительные объявления и определения типов без особых усилий. это не раздражает, потому что помогает уменьшить ваши зависимости и гарантирует, что они все правильные и видимые. на самом деле больше ничего не нужно поддерживать, поскольку другие файлы ссылаются на заголовок «типы пакетов».
Common.h (соберите их все в один файл). Это убивает возможность многократного использования, переплетая множество не связанных между собой типов. Теперь вы не можете просто взять один объект и переместить его в другой проект. Это не стартер.
пакетные зависимости и включения превосходны (идеально, правда) - не исключайте этого. вам, очевидно, придется создавать интерфейсы пакетов (или библиотеки), которые хорошо спроектированы и структурированы и представляют связанные классы компонентов. Вы делаете ненужную проблему из-за повторного использования объекта / компонента. свести к минимуму статические данные библиотеки и позволить фазовым связям и полосам выполнять свою работу. опять же, сохраняйте ваши пакеты небольшими и пригодными для повторного использования, и это не будет проблемой (при условии, что ваши библиотеки / пакеты хорошо спроектированы).
Какая-то необычная магия #define, которую использует typedef, если она еще не определена. У меня непреодолимая неприязнь к препроцессору, потому что я думаю, что новым людям трудно уследить за кодом, но, возможно, ....
на самом деле вы можете объявлять typedef в одной и той же области видимости несколько раз (например, в двух отдельных заголовках) - это не ошибка.
объявление определения типа в одной и той же области видимости с различными базовыми типами является ошибкой. очевидно. вы должны избегать этого, и, к счастью, компилятор обеспечивает это.
, чтобы избежать этого, создайте «трансляцию сборки», которая включает в себя мир - компилятор будет отмечать объявления типов с неопределенными типами, которые не совпадают.
Попытка прокрасться с минимальными typedefs и / или forwards (которые достаточно близки для освобождения при компиляции) не стоит усилий. иногда вам понадобится куча условной поддержки для предварительных объявлений - как только это определено, это легко (библиотеки stl - хороший пример этого - если вы также объявите вперед template<typename,typename>class vector;
).
Лучше всего, чтобы все эти объявления были видны, чтобы немедленно отследить любые ошибки, и вы можете избежать препроцессора в этом случае в качестве бонуса.
Используйте векторный подкласс, а не typedef. Это кажется опасным ...
подкласс std::vector
часто помечается как "ошибка новичка". этот контейнер не предназначен для использования в подклассах. не прибегайте к плохим практикам, просто чтобы сократить время компиляции / зависимости. если зависимость действительно настолько значительна, вы, вероятно, должны в любом случае использовать PIMPL:
// <package>.types.hpp
namespace MON {
class FooListPtr;
}
// FooListPtr.hpp
namespace MON {
class FooListPtr {
/* ... */
private:
shared_ptr< vector< shared_ptr<const Foo> > > d_data;
};
}
Есть ли здесь лучшие практики? Как они получаются в реальном коде, когда многократное использование, удобочитаемость и последовательность имеют первостепенное значение?
в конечном счете, я нашел небольшой лаконичный пакетный подход, который лучше всего подходит для повторного использования, для сокращения времени компиляции и минимизации зависимости.