关于C++的STL中list的理解
list是C++ stl的一个很普通的容器。这篇文章不会去讨论每种接口的用法,我认为那只是流于表面的应用,网上有很多例子。
先拿一个简单的接口看一下:
void push_back ( const T& x );
它的说明如下
Add element at the end
Adds a new element at the end of the list, right after its current last element. The content of this new element is initialized to a copy of x.
This effectively increases the list size by one.
上面这些话的意思是:将一个元素x加到list的尾部,加入的内容是x的一份拷贝。这句话很重要,我们push_back的只是一个对象的副本。
因此,假如我们需要将对象放在list容器里面去管理,同时我们又会在其他流程里面更新这些对象的信息,那么list内的副本信息时不会受到任何修改的。
这显然不是我们要的结果。因此,我们用list管理对象的时候,最后传入所要管理对象的指针。
由此,会引出另外一个问题。我们先看一下另外一个接口:
void pop_front ( );
它的说明如下:
Delete first element
Removes the first element in the list container, effectively reducing the list size by one.
This calls the removed element's destructor.
重点看最后一句话,当这个对象被pop出来后,这个对象的析构函数会被调用。假如我们一开始push_back的是一个对象,那么根据之前的讨论,实际上存入的是该对象的副本,‘
当pop的时候,副本的析构函数会被调用。但是如果我们一开始push_back的是对象的指针呢?那么该对象会不会被析构呢?
答案是不会。原因是,像指针,int,double这种都是基本的数据类型,不是对象,不会被析构。
看一段代码吧:
class TEST { public: TEST() { cout << "constructor" << endl; return; } ~TEST() { cout << "deconstruction" << endl; } }; void func(void) { TEST *test = new TEST(); std::list<TEST*> testList; testList.push_back(test); testList.pop_front();
return; } void gunc(void) { TEST test; std::list<TEST> testList; testList.push_back(test); test = testList.front(); testList.pop_front(); }
#include<iostream> #include <list> using namespace std; int main(int argc, char**argv) { func(); cout<<"--------分割线---------"<<endl; gunc(); return 0; }
分析:
func内,我们new了一块动态内存,并将该指针放入了list里面,然后我们又把它pop出来,但是整个函数执行完成后,都没有调用析构函数,这就造成了内存泄露。
gunc内,我们生成了一个局部对象test,并将对象push进了list内,根据前面的讨论我们知道实际上push进去的是test的副本,因此pop的时候调用的
析构函数,实际上是test副本的析构函数,当结束当前调用栈的时候,局部变量test的析构函数被自动调用,因此可以看到两次析构的打印。