簡體   English   中英

C ++:將對象推入向量

[英]C++ : Pushing an object into a vector

來自C的背景,我試圖自學C ++。 我一直在嘗試實現UnionFind數據結構。 我的課如下:

class UnionFind
{
private:
    int count;
    UnionFind* parent;
    int val;

public:
    UnionFind(int _val) : count(1), parent(this), val(_val) {
        printf("UnionFind(): parent=%p this=%p\n", parent, this);
        }

    ~UnionFind() {
        printf("~UnionFind()\n");
    }

    int getcount()
    {
        if (parent == this)
            return count;
        return Find()->count;
    }

    int getval() { return val; }
    void setparent(UnionFind* _parent) { parent = _parent; }
    void setcount(int _count) { count = _count; }

    // Does a union of 2 sets
    void Union(UnionFind* u)
    {
        printf("Union(%d: this=%p, %d: u=%p)\n", val, this, u->getval(), u);
        UnionFind* this_parent = Find();
        UnionFind* u_parent = u->Find();
        printf("this_parent=%p u_parent=%p\n", this_parent, u_parent);

        if (this_parent == u_parent)
            return;

        if (this_parent->getcount() > u_parent->getcount()) {
            this_parent->setcount(this_parent->getcount() + u_parent->getcount());
            u_parent->setparent(this_parent);
        } else {
            u_parent->setcount(this_parent->getcount() + u_parent->getcount());
            this_parent->setparent(u_parent);
        }
    }

    // Returns the parent
    UnionFind* Find()
    {
        //printf("%d: Find(%p) = ", val, this);
        UnionFind* temp = parent;
        while (temp != temp->parent)
            temp = temp->parent;
        //printf("%p\n", temp);
        return temp;
    }
};

稍后,我嘗試使用一些UnionFind實例填充向量,如下所示:

vector<UnionFind> vecs;
for (int i = 0; i < N; i++)
    vecs.push_back(UnionFind(i));

運行此代碼表明,UnionFind對象都具有相同的地址。 我懷疑(並確認)這是因為在每次循環迭代中都調用了UnionFind的析構函數。

我的問題是:

  • 我意識到我可以創建一個指向UnionFind對象的指針的矢量作為vector<UnionFind*>來解決此問題,但這真的是要走的路嗎? 我讀到的內容與C語言不同,它可能無需使用new / malloc或delete / free就能解決C ++中的許多問題。 解決此問題的C ++方法是什么?

[編輯]

錯字糾正。

[編輯2]

我正在嘗試實現不相交集/聯合查找數據結構。 “父”一開始會指向自身,但是隨着聯合的發生,父可能指向另一個對象。

[編輯3]

添加完整代碼。

這里有一些影響,您誤解了正在發生的事情。 創建vector<UnionFind *>並動態使用內存分配將解決您的問題的症狀,而不是根本原因。

首先,在循環的每次迭代中

vecs.push_back(UnionFind(i));

構造一個臨時UnionFind對象,將其副本存儲在向量中,然后銷毀該臨時對象。 盡管不能保證,但是沒有什么可以阻止所有臨時人員具有相同地址的。

其次,當使用int參數調用構造函數時,每個對象都在parent成員中存儲其自己的地址。 如果臨時對象是在同一地址創建的,則它們的parent成員均相等。 還要注意,程序的輸出將僅包含有關main()創建的臨時信息。

第三,當向量的push_back()附加接收到的對象的COPY時,它將復制該對象(通常使用復制構造函數)。 您的代碼尚未實現副本構造函數,因此編譯器會自動生成一個副本構造函數。 編譯器生成的復制構造函數(和賦值運算符)按VALUE復制所有成員。 因此,在復制UnionFind對象以創建另一個對象時,新創建的對象將使parent成員指向原始對象。 因此,假設循環中的每個對象都具有相同的地址,則每個COPIED對象將具有相等的parent成員。

第四,由於您僅實現了一個構造函數,因此您的輸出僅包含main()創建的臨時信息。 您將完全看不到矢量中存儲的那些臨時副本的信息。

也可以更簡單地看到相同的效果;

  UnionFind a(42);
  UnionFind b(a);

其創建兩個對象( b為的COPY a ),但你只能看到關於信息a被輸出(即有兩個目的,但打印大約只有它們中的一個信息)。 如果您還想查看有關b信息,則需要實現一個復制構造函數來完成這項工作,例如:

UnionFind(const UnionFind &rhs) : count(rhs.count), parent(this), val(rhs.val)
{
    printf("UnionFind(): parent=%p this=%p\n", parent, this);
}

如果實現復制構造函數,通常通常也需要實現其他成員函數。 查找“三元規則”-一個像您一樣需要手工復制構造函數的類,通常也需要手工賦值運算符和手工破壞函數。 另外,我在上面的描述中也過分簡化,因此(在C ++ 11及更高版本中)查找“ 5則規則”,因為您可能還需要手動實現move構造函數以正確跟蹤對象。

但是,更一般而言,如果您想學習C ++,最好避免類比於C。最好在C ++中有效的技術在C ++中通常無效,反之亦然。 學習C ++ I / O而不是堅持使用CI / O(您可以在C ++中使用CI / O的事實並不意味着它在C ++中的有效性就不如在C中。) 避免在C ++中使用malloc()free() ,因為它們對具有非平凡的構造函數和析構函數的C ++類類型不起作用。 實際上,完全避免在C ++中使用動態內存分配-在大多數情況下,還有更安全的選擇。

您的聯合查找對象在向量中並非都具有相同的地址。 您正在堆棧上構造一個對象,堆棧對象具有相同的地址。 然后對其進行復制構建,並將副本放置在向量中。

std :: vector中的append函數在哪里?

錯誤:“ std :: vector>”中沒有名為“ append”的成員

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM