1

私は長年の読者であり、初めてのポスターです...私は、今本当に頭がおかしくなっている何かに対する答えを見つけるのに苦労しました. 私はこれがうまくいくはずだと信じているので、何かが欠けているに違いありません...

渡されたオブジェクトの独自のコピーを含むデータテーブル クラスを作成しようとしています。このデータを含めるために 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);
}

私が気づいているのは、私のデータがあまりにも早く削除されていることです。私は何かを見逃したと思います...ポインタによって参照されるデータのコピーを作成し、新しくインスタンス化されたポインタをマップに保存していると思っていました...何か考えはありますか? どんな助けにも感謝します!

4

2 に答える 2

0

実際にオブジェクトのコピーを作成しているように見えますが、release() すると、VarContainer が解放されます (すべてのアイテムを削除して clear() を使用する) ため、以前に作成したコピー (ポインターのコピーを使用) 、実際のコンテナーではありません) には、空のコンテナーへのポインターが残されます。

于 2012-10-08T19:18:07.537 に答える
0

したがって、コンテナーで生のポインターを使用 (所有) する際の問題の 1 つは、インスタンスを自分で手動で削除する必要があることです。まさにそれをmyObj::~myObj行うと思います(コンテナ自体を削除する前に、すべての要素を削除するコンテナを繰り返します)。

この線:

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

データから myObj を作成するコピーです。

残念ながら、myObj のコピー コンストラクターを定義していないため、コンパイラーはポインターをVarContainerメンバーにコピーするだけのコンストラクターを生成します。マップの新しいコピーや内部で参照するものは作成されません。コピーが作成されると、2 つのインスタンスが同じコンテナーを指し、両方のインスタンスがそれを所有していると認識します。最初のインスタンスが破棄されると、問題ないように見えますが、実際には解放されたメモリを指している他のインスタンスが残ります。最長寿命のインスタンスがこのコンテナー ポインターを使用して何かをしようとするとすぐに、何か悪いことが起こります。

ポインターではなく値でマップを保存することで、これを修正できます。

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 )

于 2012-10-08T19:57:49.937 に答える