2010-09-22 109 views
3

我有一個類X,我想將它放入std :: map類型的STL映射中。 STL地圖需要將X存儲在內存中,所以我正在尋找一種有效的(運行時間和內存)方式來創建X並將其存儲在地圖中。STL映射值構造函數

我注意到,下面的代碼,其中x是X型和stlMap的一個目的是地圖上的類型的std ::地圖:

stlMap["test"] = x; 

結果在下面被稱爲:

  1. X默認的構造函數
  2. X拷貝構造函數
  3. X拷貝構造函數
  4. X的析構函數
  5. X的析構函數
  6. X分配構造
  7. X的析構函數

爲什麼要創建這麼多的X對象?

它是時間和內存的低效使用嗎?

有沒有更好的方法將對象放入地圖?也許改變地圖是一個字符串映射到x *?

+0

你試過開啓優化我會刪除很多這些。 – 2010-09-22 18:05:38

回答

5

嘗試stlMap.insert(map<string, X>::value_type("test", x))

#include <iostream> 
#include <string> 
#include <map> 

using namespace std; 

class X 
{ 
public: 
X() { cout << "X default constructor" << endl; } 
~X() { cout << "X destructor" << endl; } 
X(const X& other) { cout << "X copy constructor" << endl; } 
X& operator=(const X& other) { cout << "X copy-assignment operator" << endl; } 
int x; 
}; 


int main() 
{ 
X x; 
map< string, X > stlMap; 

cout << "INSERT BEGIN" << endl; 
stlMap.insert(map< string, X >::value_type("test", x)); 
cout << "INSERT END" << endl; 
stlMap.clear(); 
cout << "ASSIGN BEGIN" << endl; 
stlMap["test"] = x; 
cout << "ASSIGN END" << endl; 

return 0; 
} 

在我的G ++是whittles下來到:

  1. X拷貝構造函數
  2. X拷貝構造函數
  3. X的析構函數

編輯:每ArunSaha的uggestion,更新了測試。插入()輸出不變,而分配順序是這樣的:

  1. X默認的構造函數
  2. X拷貝構造函數
  3. X拷貝構造函數
  4. X的析構函數
  5. X的析構函數
  6. X複製賦值運算符
+1

+1:我在想同一個實驗......你可以在複製賦值運算符中添加一個'cout'並重新運行實驗嗎? – Arun 2010-09-22 18:19:56

+0

@ArunSaha:好抓,知道我忘了東西:)更新。 – genpfault 2010-09-22 19:04:49

+0

完美,謝謝。我會嘗試value_type操作。 – 2010-09-23 12:50:58

3

STL容器有複製語義,所以你觀察到的是典型的。

您可以改用指針,但可以通過使用智能指針(以少量開銷爲代價)避免相關的內存管理痛苦。

+0

+1從地圖重定向 2010-09-22 16:53:29

0

STL在複製和分配的基礎上工作。因此預計會有一些複製和分配。關於爲什麼有這麼多的一種方法是在X代碼中將斷點放在合適的位置,然後在調試器中運行程序。

以目前的方式,std::map正在做X的內存管理。如果你切換到使用,那麼你必須自己做內存管理。我發現前者在大多數情況下都適用。

0

是建造順序和destr當您啓用優化時,哪些因素會有所不同?許多編譯器在優化時可以省略涉及這些語句的臨時對象。我猜測輸出在優化時會涉及更少的對象。

C++ 0x大大改善了這種情況,移動構造函數。如果你的類X有一個移動構造函數(看起來像X x(X&& m) { ... },那麼你可以把你的語句改成stlMap["test"] = std::move(x);。這個語句基本上等同於構造一個X然後把它移到地圖的所有權上。如果你不避讓++ 0x中移動的語義,它是有用的東西

1

使用此作爲參考。

#include <iostream> 
#include <map> 

class X 
{ 
    public: 
    X()     { std::cout << "Default Construct\n";} 
    ~X()     { std::cout << "Destroy\n";} 
    X(X const&)   { std::cout << "Copy Construct\n";} 
    X& operator=(X const&) { std::cout << "Assignment\n";} 
}; 


int main() 
{ 
    std::map<int,X>  store; 
    X     x; 
    X     y; 

    std::cout << "Inserting x\n"; 
    store[1] = x; 
    std::cout << "Finished Insert\n"; 
    std::cout << "Inserting y\n"; 
    store[1] = y; 
    std::cout << "Finished Insert\n"; 
} 

運行,我們得到以下的輸出:

Default Construct     Building X 
Default Construct     Building Y 
Inserting x       ---- Start of an insert 
Default Construct     -------- Work to insert an item that is not in the map 
Copy Construct       
Copy Construct      
Destroy        
Destroy        -------- Finished work to insert a new item 
Assignment       Assign x into the internal object 
Finished Insert      ---- Done 
Inserting y       ---- Start of an insert 
Assignment       Assign y onto the internal object. 
Finished Insert      ---- Done 
Destroy        Destroy y 
Destroy        Destroy x 
Destroy        Destroy map containing one X