【问题标题】:vector destroys objects but does not construct their replacements?向量破坏对象但不构造它们的替换?
【发布时间】:2016-02-05 12:08:34
【问题描述】:
#include <iostream>
#include <vector>
using namespace std;

class cMember
{
    public: 
    int id;

    cMember();
    ~cMember();
};

cMember::cMember()
{
    cout<<"member constructor\n";
}

cMember::~cMember() 
{
    cout<<"member destructor\n";
};

class cDirectory
{
    std::vector<cMember> memberList;

public:
    cDirectory();
    ~cDirectory();

    void Populate();
};


cDirectory::cDirectory()
{
    cout<<"directory constructor\n";
}

cDirectory::~cDirectory()
{
    cout<<"directory desctructor\n";
}

void cDirectory::Populate()
{
    for(int i = 0; i < 2; i++)
    {
        cout<<"A\n";
        cMember t;
        memberList.push_back(t);
        cout<<"B\n";
    }
    cout<<"C\n";
}

int main( int argc, const char ** argv )
{
    cDirectory dir;
    dir.Populate();
    exit(0);
}

看看这个程序的输出,第二次迭代调用了 A 和 B 之间的成员析构函数。我假设这个调用是向量重新分配和重新填充,并在重新分配之前销毁它在其中的成员。

vector 怎么会破坏对象,而不是构造它们的替代品?

【问题讨论】:

  • 阅读“3 规则”。您的类中也应该有一个复制构造函数和赋值运算符。
  • 如您所说,vector 通过调用复制构造函数进行深层复制
  • 如果你想调用默认构造函数而不是复制构造函数,你可以emplace()新元素。

标签: c++ vector constructor destructor push-back


【解决方案1】:

矢量如何破坏对象,但不构造它们 替代品?

它通过调用对象的复制构造函数而不是用户定义的默认构造函数来构造它们。

也就是说,如果您没有为对象定义一个复制构造函数,编译器将为您隐式定义一个。这也是这里的情况。当向量的缓冲区被重新分配时,每个对象的复制构造函数都会被调用,以便将对象复制到它们的新位置。如果您将复制构造函数定义如下,您可以看到这一点:

class cMember {
public: 
  int id;
  cMember();
  CMember(cMember const&);
  ^^^^^^^^^^^^^^^^^^^^^^^^
  ~cMember();
};

cMember::cMember(cMember const &) {
    cout<<"member copy constructor\n";
}

LIVE DEMO

【讨论】:

    【解决方案2】:

    因为cMember 是静态分配的,所以当函数超出范围时,内存会丢失。如果向量在内存中仍然有对该点的引用,这对于向量来说将是有问题的。因此,std::vector 将复制构造该对象。这为向量提供了自己的动态分配副本,即使在函数超出范围后,该向量也会存在。

    我也修改了您的代码以打印this,这是输出:

    directory constructor
    A
    member constructor 0x7fff572e86f8
    B
    member destructor 0x7fff572e86f8
    A
    member constructor 0x7fff572e86f8
    member destructor 0x7fc1dbc04c80
    B
    member destructor 0x7fff572e86f8
    C
    

    如您所见,在 A 和 B 之间被销毁的对象不是由您的函数构造的。相反,它是std::vector 使用的复制构造对象。

    【讨论】:

    • 这个答案有道理,但是我的问题出现了,因为实际情况比我发布的代码示例要复杂一些。添加一个指向 cMember 的指针并在析构函数中删除它,这成为一个问题。很抱歉在原始问题中没有说清楚。有没有典型的处理方式?
    • 您需要编写一个自定义复制构造函数,并在该复制构造函数中为该副本分配新内存(而不仅仅是分配指针)。或者,如果您不想每次都分配更多内存并且两个对象应该使用相同的指针(只是没有释放问题),您可以考虑使用 C++11 中的智能指针:en.cppreference.com/w/cpp/memory/shared_ptr
    • 我认为我已经避免了整个问题,只是从不推送静态分配的对象。当不再需要指向的对象时,我总是使用指针向量和清理例程。感谢您的解释和解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-05
    • 2020-06-12
    • 1970-01-01
    • 2015-05-12
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多