实验与矢量的复制结构

时间:2012-01-14 14:07:53

标签: c++

在尝试通过'按值传递'和随后的破坏来试验复制构造时,我尝试了这段代码:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Rock{
int sz;
public:
Rock():sz(0){cout<< "Default ctor"<<endl;}
~Rock(){cout<< "Dtor"<<endl;}
Rock(const Rock& r){ cout << "Copy ctor" << endl; sz = r.sz;}
Rock& operator=(const Rock& r) {cout << "In assignment op" << endl; sz = r.sz;}
};

int main()
{
vector<Rock> rocks;
Rock a, b, c;
rocks.push_back(a);
rocks.push_back(b);
rocks.push_back(c);
return 0;
}

得到以下输出。一直到第7行都很好,但是我无法理解从那时起会发生什么。有人可以澄清吗?

Default ctor
Default ctor
Default ctor
Copy ctor
Copy ctor
Copy ctor // all fine I got it...
Dtor
Copy ctor
Copy ctor
Copy ctor
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor

3 个答案:

答案 0 :(得分:3)

让我们将输出关联到相应的代码行。

Rock a, b, c;

Default ctor
Default ctor
Default ctor

那个你可能已经想到了自己。 : - )

rocks.push_back(a);

Copy ctor

同样,你可能正确地想出来了。

rocks.push_back(b);

Copy ctor
Copy ctor // all fine I got it...
Dtor

您的评论显然是错误的,因为您几乎肯定将两个构造函数调用与此语句关联: - )

当添加a的副本时,该向量仅分配了足够的内存来存储a的一个副本(它将被允许分配)更多,但)。因此,它必须分配一个足够大的内存块来保存a b的副本,复制{{1}的副本它存储在旧内存块中,然后复制到新内存块,然后复制a,然后在释放(现在不再需要)原始内存块之前销毁b的原始副本。

a

从上面的解释,你现在应该可以猜出这里发生了什么。

但是请注意,如果你将另一个元素推回到向量中,很可能你再次得到一个复制构造函数而没有析构函数调用。这是因为向量的典型策略是在每个步骤中将分配的内存加倍,因此当推回rocks.push_back(c); Copy ctor Copy ctor Copy ctor Dtor Dtor 时,它最有可能为4个对象分配空间。实际上c需要使用指数策略(不需要使用因子2,并且有人认为黄金均值是一个更好的因素)。

std::vector

此处三个对象} Dtor Dtor Dtor Dtor Dtor Dtor cb,然后向量中的三个对象被破坏。

答案 1 :(得分:1)

每当std::vector必须增加其容量时(因为您要推送更多元素),它需要分配新存储,将所有现有元素从旧存储复制到新存储,然后删除旧元素。因此,您将获得对复制构造函数和析构函数的“额外”调用。

如果您在对cout的每次通话之间加上push_back声明,则应该有助于说明哪些ctor / dtor通话与每个push_back相关联。

但这是我对年表的猜测:

Default ctor
Default ctor
Default ctor

// First push_back() (capacity initially 1)
Copy ctor    // Copy a into vector

// Second push_back() (capacity now grows to 2)
Copy ctor    // Copy rocks[0] to new storage
Copy ctor    // Copy b into vector
Dtor         // Destruct rocks[0] in old storage

// Third push_back() (capacity now grows to 4)
Copy ctor    // Copy rocks[0] to new storage
Copy ctor    // Copy rocks[1] to new storage
Copy ctor    // Copy c into vector
Dtor         // Destruct rocks[0] in old storage
Dtor         // Destruct rocks[1] in old storage

// End of main
Dtor         // Destruct rocks[0]
Dtor         // Destruct rocks[1]
Dtor         // Destruct rocks[2]
Dtor         // Destruct c
Dtor         // Destruct b
Dtor         // Destruct a

答案 2 :(得分:1)

很容易修改代码以打印更多信息:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Rock{
    int sz;
public:
    Rock():sz(0){cout<< "Default ctor"<<endl;}
    Rock(int x):sz(x){cout<< "int ctor " << x <<endl;}
    ~Rock(){cout<< "Dtor " << sz <<endl;}
    Rock(const Rock& r){ cout << "Copy ctor from " << r.sz << endl; sz = r.sz;}
    Rock& operator=(const Rock& r) {cout << "Copy ctor " << sz << " from " << r.sz << endl; sz = r.sz;}
};

int main()
{
    vector<Rock> rocks;
    Rock a(1), b(2), c(3);
    rocks.push_back(a);
    rocks.push_back(b);
    rocks.push_back(c);
    return 0;
}

打印(带说明):

int ctor 1
int ctor 2
int ctor 3
Copy ctor from 1  // copies a into the vector
                  // push_back(a) returns (capacity == 1)
Copy ctor from 1  // vector reallocates to a greater storage
Copy ctor from 2  // copies b into the vector
Dtor 1            // destroy the old elements
                  // push_back(b) returns (capacity == 2)
Copy ctor from 1  // vector reallocates to a greater storage
Copy ctor from 2  
Copy ctor from 3  // copy c into the vector
Dtor 1            // destroy the old elements
Dtor 2
                  // push_back(c) returns (capacity == 4)
Dtor 3            // destroy the local a, b, c
Dtor 2
Dtor 1
Dtor 1            // destroy the vector and its elements
Dtor 2
Dtor 3