2012-10-08 204 views
1

我是一位長期讀者,並且是第一次發佈海報......我搜索了很長時間,很難找到一個現在令我難以置信的東西的答案。我必須錯過一些東西,因爲我相信這應該工作...C++複製指針指向的數據

我想創建一個數據表類,它將包含它自己的傳遞給它的對象的副本。我決定使用std :: map來包含這些數據。請參閱下面的示例代碼:

typedef std::map <std::string, myVar *> myVarContainer; 

class myObj 
{ 
    public: 
     myObj(void); 
     virtual ~myObj(void); 

     void setVar(std::string Key, myVar & Var); 

     myVar * getVar(std::string Key); 

     void release() 
     { 
      for (myVarContainer::iterator i = VarContainer->begin(); i != VarContainer->end(); ++i) 
      { 
       delete (i->second); 
      } 

      VarContainer->clear(); 
     }; 

     myVarContainer * VarContainer; 

}; 

typedef std::map <myVar, myObj *> myRow; 

class myTable 
{ 
    public: 
     myTable(void); 
     virtual ~myTable(void); 

     void addDataPoint(myVar RowID, myVar ColID, myObj * Data) 
     { 
      std::map <myVar, myRow *>::iterator i = m_Rows->find(RowID); 

      if (i == m_Rows->end()) 
      { 
       m_Rows->insert(make_pair(RowID, new myRow())); 
      } 
      i = m_Rows->find(RowID); 

      // i thought the below line would be creating a copy of the data? 
      // I thought this logic went: 
      // 1. create a new object copied from the value of 'Data' 
      // 2. return a pointer to this object and pair with the 'colID' 
      // 3. make this into a pair and insert into the main map 
      i->second->insert(make_pair(ColID, new myObj(*Data))); 
     }; 

    protected: 

     std::map <myVar, myRow *> * m_Rows; 
} 


int main() 
{ 

    myVar a, b, c, d; 

    myObj * o = new myObj(); 

    o->setVar("test", a); 
    o->setVar("test2", b); 

    myTable * tab = new myTable(); 

    myVar x1, y1, x2; 

    tab->addDataPoint(y1, x1, o); 

    o->release(); // this clears out both 'o' and the values in 'tab'!?!? 

    //at this point tab has no data in its object at y1,x1??? 

    o->setVar("test3", c); 
    o->setVar("test4", d); 

    tab->addDataPoint(y1, x2, o); 
} 

我注意到的是我的數據被刪除得太早。我相信我錯過了一些東西......我原以爲我正在創建一個由指針引用的數據的副本,然後在我的地圖中存儲一個新的實例化指針......任何想法?我感謝任何幫助!

+1

MyObj中類無法實現複製構造函數,所以做任何複製將是淺薄! –

回答

0

因此,在容器中使用(擁有)原始指針的問題之一是您需要自己手動刪除實例。我認爲myObj::~myObj就是這樣做的(迭代容器在刪除容器本身之前刪除所有元素)。

行:

i->second->insert(make_pair(ColID, new myObj(*Data))); 

是複製構建從數據MyObj中。

不幸的是,因爲你沒有爲myObj定義一個拷貝構造函數,所以編譯器會爲你生成一個拷貝,它只會將指針複製到VarContainer成員。它不會創建地圖的新副本或其內部引用的任何內容。一旦創建了一個副本,就會有兩個實例指向同一個容器,並且兩個實例都認爲它們擁有它。當第一個被破壞時,它會好起來的,但實際上讓另一個實例指向釋放的內存。只要最長的實例試圖使用這個容器指針來做任何事情就會發生一些不好的事情。

你可以通過指針存儲由價值的地圖,而不是解決這個問題:

typedef std::map<std::string, myVar> myVarContainer; 
typedef std::map<myVar, myObj> myRow; 

也改變myObj::VarContainer是未分配的成員。這意味着現在所有東西都可以正確複製,並且副本不會引用原始內容。

請注意,您也可以使用智能指針(例如std::shared_ptr)而不是原始指針,但您仍然需要小心,因爲雖然複製是安全的,但它們與原始數據共享數據可能不是你的期望。

你應該在下面一起來看看:

http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming

+0

謝謝!我忽略顯式定義一個複製構造函數,這意味着varcontainer指針(不是值)將被複制...感謝一堆! – user1729715

0

看來您確實正在創建對象的副本,但是當您釋放()時,您將釋放VarContainer(刪除所有項目並使用clear()),因此您之前創建的副本(帶有指針的副本,而不是實際的容器)剩下一個指向空容器的指針。

+0

如何正確更改我的'make_pair'語句? 也許它只是一個漫長的一天,但我的印象是 新的myObj(*數據)正在創建一個新的指針,從myObj'數據'複製一個新的myObj? – user1729715

+0

問題是,它會爲您的「myVarContainer * VarContainer」指針創建一個副本,而不是您調用release()時刪除的容器的副本。 爲了證明這一點(可能不是一個好的解決方案),請註釋掉你的release()調用。 – imreal