2012-10-08 321 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