2010-02-07 29 views
0

帮助这里是代码:需要与理解STL向量(在邮件的正文简单的代码)

#include <vector> 
#include <iostream> 

class A 
{ 
public: 
    A() { std::cout << __FUNCTION__ << "\n"; } 
    ~A() { std::cout << __FUNCTION__ << "\n"; } 

    A& operator=(const A&) { std::cout << __FUNCTION__ << "\n"; return *this;} 
}; 

int main(int argc, char* argv[]) 
{ 
    std::vector<A> as; 
    A a; 
    as.push_back(a); 
    as.push_back(a); 
    return 0; 
} 

这里是我得到的输出:

A::A 
A::~A 
A::~A 
A::~A 
A::~A 

我理解的输出第一行是从创建'a'时从调用到c-tor。对d-tor的一个要求也属于a。 另外三个对A ::〜A()的调用呢,它们来自哪里? 为什么有更多的d-tor调用比c-tor的调用要多? 容器在向其元素添加副本时如何克隆“a”? 最后,是输出实现定义还是还有其他可能的输出?

回答

2

要了解发生了什么,你缺少在一种方法:

A(const A&) { std::cout << __FUNCTION__ << "(const A&)\n"; } 

然后你可以看到输出:

A() 
A(const A&) 
A(const A&) 
A(const A&) 
~A 
~A 
~A 
~A 

什么发生的是,对于每一个的push_back矢量分配一个新的连续数组,复制旧内容并销毁它。如果你计算,第一个拷贝构造函数是第一个push_back,第二个和第三个是下一个push_back。第一个析构函数用于第二个push_back,第二个析构函数用于销毁矢量,最后一个用于销毁变量a。

顺便说一句,这是完全实现定义的,因为它可以通过块进行分配,这将防止相当多的复制/销毁。你甚至可以通过使用vector::reserve(size_type n)自己块。

3

您需要添加一个拷贝构造函数:

A(const A&) { std::cout << __FUNCTION__ << "\n"; } 

的载体,像所有其他标准库容器,商店副本 - 这些副本与拷贝构造函数取得。不过,您应该知道,有几个地方编译器可以用来避免复制构建,甚至可以制作额外的副本,因此您的输出可能不完全符合您的期望。

0

正如我确信你意识到你正在堆栈上创建你的“A”对象,然后将它们复制到数组中(正如其他答案所暗示的),暗示使用拷贝构造函数。

如果你的A对象是拥有数据的真实数据对象,或者难以复制的复杂状态,你可能需要考虑在你的数组中存储指针,而不是直接存储对象。你需要自己管理记忆,但这是一个值得考虑的问题。

int main(int argc, char* argv[]) 
{ 
    std::vector<A*> as; 
    A *a = new A(); 
    as.push_back(a); 
    as.push_back(a); 
    return 0; 
} 

你会看到输出:

A() 

由于只有一个实例对象已经创建和数组只是存储指针的副本。很显然,在某些时候,您需要通过其中一个指针删除对象本身,以确保最终获取内存。