C ++指针指向的数据

时间:2012-10-08 19:12:18

标签: c++ pointers map reference copy-constructor

我是一位长期读者,也是第一次发布的海报......我一直在寻找能够找到真正令人难以置信的事情的答案。我必须遗漏一些东西,因为我相信这应该有用......

我正在尝试创建一个数据表类,它将包含它自己传递给它的对象的副本。我决定使用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);
}

我注意到的是我的数据被过早删除了。我相信我错过了一些东西......我以为我正在创建指针引用的数据副本,然后在我的地图中存储一个新的实例指针......有什么想法?我感谢任何帮助!

2 个答案:

答案 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