我是一位长期读者,也是第一次发布的海报......我一直在寻找能够找到真正令人难以置信的事情的答案。我必须遗漏一些东西,因为我相信这应该有用......
我正在尝试创建一个数据表类,它将包含它自己传递给它的对象的副本。我决定使用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);
}
我注意到的是我的数据被过早删除了。我相信我错过了一些东西......我以为我正在创建指针引用的数据副本,然后在我的地图中存储一个新的实例指针......有什么想法?我感谢任何帮助!
答案 0 :(得分:0)
看来你确实正在创建该对象的副本,但是当你释放()时,你正在释放VarContainer(删除所有项目并使用clear()),所以你之前创建的副本(带有副本)指针,而不是实际的容器)留下一个指向空容器的指针。
答案 1 :(得分:0)
因此,在容器中使用(拥有)原始指针的一个问题是您需要自己手动删除实例。我假设myObj::~myObj
只是这样做(在删除容器本身之前迭代容器删除所有元素)。
该行:
i->second->insert(make_pair(ColID, new myObj(*Data)));
是否从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)