2

我编写了这段代码来检查 c++ 中析构函数的行为

#include <vector>
#include <iostream>

using namespace std;


class WrongDestructor
{
private:
    int number;
public:
    WrongDestructor(int number_) :
    number(number_)
    {}

    ~WrongDestructor() {

    cout<<"Destructor of " <<number<<endl;

//  throw int();
    }
};
int main(int argc, char *argv[])
{
    std::vector<WrongDestructor> wrongs;

    for(int i = 0; i < 10; ++i) {
    wrongs.push_back(WrongDestructor(i));
    }

    return 0;
}

我发现有趣的是我的程序的输出:

Destructor of 0
Destructor of 0
Destructor of 1
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 4
Destructor of 5
Destructor of 6
Destructor of 7
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 4
Destructor of 5
Destructor of 6
Destructor of 7
Destructor of 8
Destructor of 9
Destructor of 0
Destructor of 1
Destructor of 2
Destructor of 3
Destructor of 4
Destructor of 5
Destructor of 6
Destructor of 7
Destructor of 8
Destructor of 9

这意味着创建的对象比我想象的要多得多。当我在 for 循环中填充集合时,我希望集合中显然有 10 个,并且可能会创建下 10 个作为临时对象。但是它们的数量更多,其中一些甚至比其他更频繁地创建。

4

4 回答 4

4

vector必须分配更大的内存块来保存元素时,新元素被移动构造到新的更大的内存块中。因为您的类型没有定义移动构造函数或复制构造函数,所以您将获得编译器提供的默认复制构造函数。默认的复制构造函数对类中的所有成员进行简单的成员复制。

此外,使用插入元素本身push_back需要将其移动或复制到vector. 因此,假设您的编译器没有对此进行优化,您也将在那里获得副本。(请注意,您可以使用 避免这些副本emplace_back。)

结果,您会提前将多个实例副本插入到容器中,因为当 eg1被复制到 内部的较大内存缓冲区中时vector,它会在旧的较小缓冲区中被销毁。

您可以通过定义复制和/或移动构造函数更清楚地看到此行为:

#include <vector>
#include <iostream>

using namespace std;


class WrongDestructor
{
private:
    int number;
public:
    WrongDestructor(int number_) :
    number(number_)
    {}

    // Copy constructor
    WrongDestructor(WrongDestructor const& copied)
        : number(copied.number)
    {
        cout << "Copied " << this->number << endl;
    }

    ~WrongDestructor() {

    cout<<"Destructor of " <<number<<endl;

//  throw int();
    }
};
int main(int argc, char *argv[])
{
    std::vector<WrongDestructor> wrongs;

    for(int i = 0; i < 10; ++i) {
    wrongs.push_back(WrongDestructor(i));
    }

    return 0;
}

该程序提供以下输出:http: //ideone.com/S5Zf41

于 2012-12-09T08:31:02.690 回答
3

您的向量没有预先确定的大小。当您将对象推回向量时,它必须重新分配向量本身以容纳新条目。这意味着将对象从内存缓冲区复制到新缓冲区。因此,您会在执行此操作时看到更多副本。

于 2012-12-09T08:30:42.200 回答
1

您可以使用std::vector::reserve为向量分配足够的空间。否则,向量需要为传入元素重新分配连续空间,这会导致大量副本。

std::vector<WrongDestructor> wrongs;
wrongs.reserve(10);
于 2012-12-09T08:32:50.507 回答
1

是的,看起来你在向量中添加了 10 个对象,但实际上又创建了 10 个对象,所以最后会销毁另外 10 个对象。

你应该知道,当vector的内容越来越多时,vector会增加它的容量来容纳更多的对象,在这个过程中发生了什么?

如果 vector 没有空间存放新对象,它将为更多对象创建更大的内存块,并复制它拥有的对象。然后添加新的(通过 push_back),然后它会破坏对象并释放满足它们的原始内存。

因此,当复制更多创建的对象时,在销毁原始对象时,会调用更多的析构函数。

最好的方法是您提供复制构造函数,并在其中提供 printf 内容。并且还在ctor中打印一些东西,你会看到整个过程。

您需要了解的更多是vector的容量和储备。

于 2012-12-09T08:42:22.747 回答