Проведя последние 2 месяца с картами еды, сна и дыхания, у меня есть рекомендация. Позвольте карте распределять свои собственные данные всякий раз, когда это возможно. Это намного чище, именно по тем причинам, которые вы выделяете здесь.
Есть также некоторые тонкие преимущества, например, если вы копируете данные из файла или сокета в данные карты, хранилище данных существует, как только существует узел, потому что, когда карта вызывает malloc () для выделения узла, он выделяет память как для ключа, так и для данных. (AKA map [key] .first и map [key] .second)
Это позволяет вам использовать оператор присваивания вместо memcpy () и требует на 1 меньше вызова malloc () - того, который вы делаете.
Здесь следует обратить внимание на несколько предостережений.
- НЕ вызывайте malloc () или new в строке кода, которая добавляет узел дерева, так как ваш вызов malloc () вернет указатель ДО того, как вызов карты для malloc () выделил место для хранения возврата из вашего таНос ().
- в режиме отладки, ожидайте, что у вас будут похожие проблемы при попытке освободить () вашу память. Обе эти проблемы кажутся мне проблемой компилятора, но, по крайней мере, в MSVC 2012 они существуют и представляют собой серьезную проблему.
немного подумайте о том, где "закрепить" ваши карты. IE: где они объявлены. Вы не хотите, чтобы они вышли из сферы по ошибке. main {} всегда безопасен.
INT _tmain(INT argc, char* argv[]) {
IC_CDR CDR, *pThisCDRLeafData=NULL;
CDR_MAP cdrMap;
CUST_MAP custMap;
KCI_MAP kciMap;
Мне очень повезло, и я очень рад, что критическая карта выделяет структуру в виде данных узла, и эта структура "привязывает" карту. В то время как C ++ отказался от анонимных структур (ужасное, ужасное решение, которое ДОЛЖНО быть отменено), карты, являющиеся членами 1-й структуры, работают так же, как анонимные структуры. Очень гладкий и чистый с нулевым размером эффектов. Передача указателя на ведомую структуру листа или копию структуры по значению в вызове функции, оба работают очень хорошо. Настоятельно рекомендуется.
- вы можете перехватить возвращаемые значения для .insert, чтобы определить, нашел ли он существующий узел по этому ключу или создал новый. (см. код № 12). Использование индексной записи не позволяет этого. Возможно, лучше остановиться на .insert и придерживаться его, особенно потому, что нотация [] не работает с мультикартами. (это не имеет смысла, так как в мультикарте нет клавиши «a», а есть серия клавиш с одинаковыми значениями)
- вы можете и должны также перехватывать возвраты для .erase и .empty () (ДА, досадно, что некоторые из этих вещей являются функциями и нуждаются в (), а некоторые, как .erase, не делают)
- вы можете получить как значение ключа, так и значение данных для любого узла карты, используя .first и .second, которые все карты, по соглашению, используют для возврата ключа и данных соответственно
сэкономьте ОГРОМНОЕ количество путаницы и печатания, и используйте typedef для своих карт, вот так.
typedef map<ULLNG, IC_CDR> CDR_MAP;
typedef map<ULLNG, pIC_CDR> CALL_MAP;
typedef struct {
CALL_MAP callMap;
ULNG Knt;
DBL BurnRateSec;
DBL DeciCents;
ULLNG tThen;
DBL OldKCIKey;
} CUST_SUM, *pCUST_SUM;
typedef map<ULNG,CUST_SUM> CUST_MAP, CUST_MAP;
typedef map<DBL,pCUST_SUM> KCI_MAP;
передать ссылки на карты, используя операторы typedef и &, как в
ULNG DestroyCustomer_callMap(CUST_SUM Summary, CDR_MAP& cdrMap, KCI_MAP& kciMap)
использовать тип переменной auto для итераторов. Компилятор определит из типа, указанного в остальной части тела цикла for (), какой тип карты использовать. Это так чисто, это почти волшебство!
for(auto itr = Summary.callMap.begin(); itr!= Summary.callMap.end(); ++itr) {
определить некоторые константы манифеста, чтобы сделать возврат из .erase и .empty () более осмысленным.
if(ERASE_SUCCESSFUL == cdrMap.erase (itr->second->iGUID)) {
учитывая, что «умные указатели» действительно просто ведут подсчет ссылок, помните, что вы всегда можете вести собственный подсчет ссылок, возможно, более понятным и более очевидным способом. Комбинируя это с # 5 и # 10 выше, вы можете написать хороший чистый код, подобный этому.
#define Pear(x,y) std::make_pair(x,y) // some macro magic
auto res = pSumStruct->callMap.insert(Pear(pCDR->iGUID,pCDR));
if ( ! res.second ) {
pCDR->RefKnt=2;
} else {
pCDR->RefKnt=1;
pSumStruct->Knt += 1;
}
использование указателя для зависания на узле карты, который выделяет все для себя, т.е. IE: нет пользовательских указателей, указывающих на объекты, созданные пользователем malloc (), работает хорошо, потенциально более эффективен и может использоваться для изменения Данные узла без побочных эффектов в моем опыте.
в той же теме, такой указатель может очень эффективно использоваться для сохранения состояния узла, как в pThisCDRLeafData
выше. Передача этой функции в функцию, которая изменяет / изменяет данные конкретного узла, является более чистой, чем передача ссылки на карту, и ключ, необходимый для возврата к узлу pThisCDRLeafData
, указывает.
итераторы не являются магией. Они дорогие и медленные, так как вы перемещаетесь по карте, чтобы получить значения. Для карты, содержащей миллион значений, вы можете прочитать узел на основе ключа со скоростью около 20 миллионов в секунду. С итераторами это, вероятно, в 1000 раз медленнее.
Я думаю, что сейчас это касается обложек. Обновится, если что-то из этого изменится или появятся дополнительные идеи, которыми можно поделиться. Мне особенно нравится использовать STL с C-кодом. IE: нигде не видно класса. Они просто не имеют смысла в контексте, в котором я работаю, и это не проблема. Удачи.