食べて、寝る、そして呼吸する地図を最後の2ヶ月間使ったので、私はお勧めします。可能であれば、地図に自分のデータを割り当てさせる。それはあなたがここで強調しているのとまったく同じ理由で、よりクリーンです。
ファイルやソケットからマップのデータにデータをコピーする場合など、ノードが存在するとすぐにデータストレージが存在します。これは、マップがmalloc()を呼び出してノードを割り当てるとキーとデータの両方にメモリを割り当てます。
これにより、memcpy()の代わりに代入演算子を使用することができ、malloc()を1回呼び出す必要がありません。
IC_CDR CDR, *pThisCDRLeafData; // a large struct{}
while(1 == fread(CDR, sizeof(CDR), 1, fp)) {
if(feof(fp)) {
printf("\nfread() failure in %s at line %i", __FILE__, __LINE__);
}
cdrMap[CDR.iGUID] = CDR; // no need for a malloc() and memcpy() here
pThisCDRLeafData = &cdrMap[CDR.iGUID]; // pointer to tree node's data
ここで指摘する価値のある注意点がいくつかあります。
- malloc関数にマップの呼び出し()を保持する場所を割り当てられた前のポインタを返します)はmalloc(にお電話としてツリーノードを追加するコードの行での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++によって破棄されていますが(ひどい恐ろしい決定は必ず元に戻す必要があります)、最初の構造体メンバであるマップは匿名の構造体のように動作します。非常に滑らかでクリーンで、サイズ効果はゼロです。リーフ所有の構造体へのポインタ、または関数呼び出しの値による構造体のコピーを渡すと、どちらもうまく動作します。強くお勧めします。
- .insertの戻り値をトラップして、そのキー上に既存のノードが存在するかどうかを判断したり、新しいノードを作成したりすることができます。 (コードについては#12を参照してください)添字表記を使用してもこれは許されません。特に[]表記がマルチマップでは機能しないため、.insertとそれに固執する方が良いかもしれません。 ( "a"キーがないので、マルチマップで同じ値を持つ一連のキーがないので、そうするのは意味がありません)
- .eraseと。空白()(はい、これらの機能のいくつかは機能していて迷惑で、()のようなものが必要です。)
- マップノードのキー値とデータ値の両方を取得できます.firstと.secondを使用して、すべての地図を慣習的にキーとデータを返すために使用します。
あなたは混乱と入力の莫大な量を節約し、マップ用のtypedefを使用します。
イテレータのための "自動" 変数タイプを使用
ULNG DestroyCustomer_callMap(CUST_SUM Summary, CDR_MAP& cdrMap, KCI_MAP& kciMap)
と同様の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;
パス参照。コンパイラは、残りのfor()ループ本体で指定された型から、使用するマップ型の型を調べます。それはとてもきれいなので、ほぼ魔法です!
for(auto itr = Summary.callMap.begin(); itr!= Summary.callMap.end(); ++itr) {
より意味のある).eraseと.empty(からのリターンを作るために、いくつかのマニフェスト定数を定義します。実際には参照カウントを維持している「スマートポインタ」は、あなたはいつも、おそらくクリーナー、そしてより多くの明白な方法で、独自の参照カウントを維持することができます覚えていることを考えると
if(ERASE_SUCCESSFUL == cdrMap.erase (itr->second->iGUID)) {
。上記の#5と#10を組み合わせることで、このようなきれいなコードを書くことができます。 、自身のためにIEをすべて割り当てマップ・ノード上にハングアップするポインタを使用
#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;
}
:NOユーザポインタがオブジェクトをED)(ユーザのmallocを指していないが、潜在的に、より効率的であり、そしてするために使用され、うまく機能します私の経験で副作用を起こすことなくノードのデータを変更してください。
同じテーマでは、上記のpThisCDRLeafData
のように、そのようなポインタを非常に効果的に使用してノードの状態を保持することができます。これを特定のノードのデータを変更/変更する関数に渡すと、マップへの参照とノードpThisCDRLeafData
に戻るために必要なキーを渡すよりもきれいです。
イテレータは魔法ではありません。値を取得するために地図をナビゲートしているので、高価で低速です。百万の値を保持するマップでは、キーに基づいてノードを1秒あたり約2,000万で読み取ることができます。イテレータでは、おそらく1000倍も遅いでしょう。
私は今のところそれについてカバーしていると思います。この変更がある場合、または共有する追加の洞察がある場合は更新されます。私は特にCコードでSTLを使うのを楽しんでいます。 IE:どこでも見えるクラスではありません。彼らは、私が取り組んでいる文脈では意味をなさない。それは問題ではない。がんばろう。
アクセスするにはat()を使用してみてください。例ではないものにはアクセスできません:http://ideone.com/ZeRTnd(以前はキー "B"の項目が定義されていましたが、map.clear )キー "B"にアクセスしようとすると '' std :: out_of_range''例外が発生する –