C ++:将对象推入向量

时间:2018-04-07 22:56:52

标签: c++ vector scope stl

来自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 ++方法是什么?

[编辑]

Typo纠正。

[编辑2]

我试图实现一个不相交集/联合查找数据结构。 &#34;父&#34;最初会指向自己,但是当工会发生时,父母可能会指向不同的对象。

[编辑3]

以完整代码添加。

2 个答案:

答案 0 :(得分:2)

这里有一些效果,你误解了发生了什么。创建vector<UnionFind *>并使用动态内存分配将处理问题的症状,但不会导致根本原因。

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

vecs.push_back(UnionFind(i));

构造一个临时的UnionFind对象,将其副本存储在向量中,然后销毁临时对象。虽然没有保证,但没有什么能阻止临时人员拥有相同的地址。

其次,当使用int参数调用构造函数时,每个对象都在其parent成员中存储自己的地址。如果临时对象是在同一地址创建的,则所有临时对象都将parent成员相等。另请注意,程序的输出仅包含有关main()创建的临时文件的信息。

第三,当向量的push_back()附加它接收的对象的COPY时,它会复制对象(通常使用复制构造函数)。您的代码尚未实现复制构造函数,因此编译器会自动生成一个。编译器生成的复制构造函数(和赋值运算符)按VALUE复制所有成员。因此,在复制UnionFind对象以创建另一个对象时,新创建的对象将使其parent成员指向原始对象。因此,假设循环中的每个对象具有相同的地址,则每个COPIED对象将具有相等的parent成员。

第四,由于您只实现了一个构造函数,因此您的输出仅包含有关在main()中创建的临时值的信息。您将看不到有关存储在向量中的临时对象的COPIES的信息。

同样的效果也可以看出,更简单地用;

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

创建了两个对象(b作为a的COPY),但您只会看到有关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的规则”,因为您可能需要手动实现移动构造函数以及正确跟踪对象。 / p>

然而,更一般地说,如果你正在尝试学习C ++,你最好避免通过类比C来避免这样做。在C语言中有效的技术在C ++中通常是无效的,反之亦然。学习C ++ I / O而不是坚持使用C I / O(你可以在C ++中使用C I / O这并不意味着它在C ++中和在C中一样有效)。避免在C ++中使用malloc()free(),因为它们不会使用具有非平凡构造函数和析构函数的C ++类类型。事实上,在C ++中完全避免使用动态内存分配 - 在大多数情况下,有更安全的替代方案。

答案 1 :(得分:1)

您的联合查找对象并非在向量中都具有相同的地址。您正在堆栈上构造一个堆栈对象具有相同地址的对象。然后它被复制构造并且副本被放置在向量中。

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

错误:'std :: vector&gt;'

中没有名为'append'的成员