[英]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的析構函數。
我的問題是:
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.