c++ STL 常用容器元素类型相关限制 指针 引用
c++ 的 STL 中主要有 vector , list, map, set , multimap,multiset
这些容器完全支持使用内置类型和指针(指针注意内存泄露问题)。
就是说乱用智能指针或其他指针作为容器元素,有可能2个元素指向同一个对象,2个元素(指针)对应一个对象,甚至更多
C++ 容器要求元素具有 object type,引用不是 object type。

#include <vector>
#include <boost/shared_ptr.hpp> using namespace std; class test {};
typedef boost::shared_ptr<test> test_ptr; int main()
{
vector<test> tmp;
vector<test*> tmp1; //小心内存泄露,重复析构等问题
//vector<test&> tmp; //直接编译通不过
vector<test_ptr> tmp2;
//vector<test_ptr&> tmp3; //即使是boost的智能指针的引用也不行 return 0;
}

这些容器都要求元素类型满足以下2种情况:
(1)能被复制:向这些容器添加新元素时,容器会复制一份自己的版本,这要求容器使用的元素类型可以被复制,类类型需要复制构造函数的支持了;
(2)能被赋值:在使用容器的删除、查找、访问、使用迭代器修改元素等许多情况下,都需要元素的赋值操作支持,类类型需要赋值操作符运算的支持。
vector、list 中的单参数的resize 操作需要默认初始化指定个数的元素,类类型需要无参数的默认构造函数支持初始化。
set、multiset, map和multimap中的键类型、 list 中的sort 操作 都需要 < 比较操作来排序,类类型需要 < 操作符运算的支持。
在STL中,容器的元素要满足三个基本要求:可拷贝(copyable)、可赋值(assignable)、可析构(destroyable)。基本数据类型和自定义的类都满足这些条件,但是引用不满足,因为引用不能析构。
======================================================
http://wenku.baidu.com/view/8d049f4f767f5acfa1c7cd11.html
【摘要】对C++语言本身来说,它并不在乎用户把什么类型的对象作为STL容器的元素,因为模板类型参数在理论上可以为任何类型。比如说STL容器仅支持“值”语义而不支持“引用(&)”语义,并非因为模板类型参数不能为引用,而是因为如果容器元素为引用类型,就会出现“引用的引用”、“引用的指针”等C++语言不支持的语法和语义。智能指针是一种模拟原始指针行为的对象,因此理论上也可以作为容器的元素,就象原始指针可以作为容器元素一样。但是智能指针毕竟是一种特殊的对象,它们在原始指针共享实值对象的基础能力上增加了自动销毁实值对象的能力,如果将它作为容器的元素,可能导致容器之间共享元素对象实值,这不仅不符合STL容器的概念和“值”语义,也会存在安全隐患,同时也会存在许多应用上的限制,特别是象STL中的auto_ptr这样的智能指针。
可以作为STL容器的元素的数据类型一般来说需要满足下列条件:
(1)可默认构造的(Default Constructible),也即具有public的default constructor,不论是用户显式定义的还是编译器自动合成的。但是用户定义的带参数的constructor(包括copy constructor)会抑制编译器合成default constructor。实际上并非任何情况下任何一种容器都强制要求其元素类型满足这一要求,特别是关联式容器,因为只有序列式容器的某些成员函数才可能明确地或隐含地使用元素类型的默认构造函数,如果你不使用这样的成员函数,编译器就不需要元素类型的默认构造函数;
(2)可拷贝构造(Copy Constructible)和拷贝赋值(Copy Assignable)的,即具有public的copy constructor和copy assignment operator,不论是编译器自动合成的还是用户显式定义的。其它版本的operator=()重载并不会抑制编译器合成copy assignment operator,如果你没有显式定义它的话。这个条件可归结为:元素必须是可拷贝的(Copyable),但实际上拷贝赋值的要求也不是强制的,原因和默认构造函数类似;
(3)具有public的destructor,不论是编译器自动合成的还是用户显式定义的; (4)对于关联式容器,要求其元素必须是可比的(Comparable)。
std::auto_ptr满足上述条件吗?至少满足前三条,因此至少可以作为序列式容器的元素;如果为auto_ptr定义了比较运算符的话,应该还可以把它作为关联式容器的元素。
但是auto_ptr的特点是接管和转移拥有权,而不是像原始指针那样可以共享实值对象,
int tmp = 10;
int* p1 = &tmp;
int* p2 = &tmp;
指针p1 p2共享实值对象tmp;
即:auto_ptr在初始化时接管实值对象和拥有权,而在拷贝时(拷贝构造和拷贝赋值)会交出实值对象及其拥有权。因此,auto_ptr对象和它的拷贝绝对不会共享实值对象,任何两个auto_ptr也不应该共享同一个实值对象。这就是说,auto_ptr对象和它的拷贝并不相同。然而根据STL容器“值” 语义的要求,可拷贝构造意味着一个对象必须和它的拷贝相同(标准中的正式定义比这稍复杂一些)。同样,可赋值意味着把一个对象赋值给另一个同类型对象将产生两个相同的对象。显然,auto_ptr不能满足这一要求,似乎与上面的结论矛盾!
STL容器管理元素的方法是动态创建元素的拷贝
应该说,从应用的方便性和安全角度出发,容器应该要求其元素对象的拷贝与原对象相同或者等价,但auto_ptr显然不满足这一条。
======================================================
http://bbs.csdn.net/topics/310036165
容器元素比如vector对元素对象的唯一要求是可以复制构造。
但比如说你把auto_ptr对象用作了容器元素,虽然其也可以复制构造,只不过复制构造会破坏原始对象,你用了之后会导致未定义现象。
容器的大小是可以改变的,而且往往会自动改变。
对于vector来说,如果空间不够了,会自动增长,但是如果原来所在的空间不够的话,系统就会在另外一个地方分配一个满足需要的空间。
所以在此时,对于vector已有的元素也进行了移动,此时就会执行新的构造函数,同样还会把原来位置的旧元素析构掉。
如果同时存在两个vector,其中一个对旧元素执行了析构,会导致另外一个对同一个元素析构,这样就会出问题。
对于你举的例子没有这样的问题,这是因为对于char*执行的值拷贝。
所谓的“值语义”就是说可不可以拷贝的问题。std::auto_ptr不满足这个条件。
"值"的语义就是 每个元素都应该是单独的完整的元素,而其元素指针共享同一对象,导致操作一个元素而影响其他元素影响整个容器。。。
std::auto_ptr这种智能指针的特性,决定了它不适合作为容器的元素的。比如用于vector时,使用push_back(),调用的是复制构造函数。
但auto_ptr在拷贝构造的同时,把原有对象的实值拥有权转给了vector,同时删除了原有的auto_ptr。可能会导致后面使用中的错误。
当使用vector.clear()或者这个vector的生存周期到了,被释放的时候,同时会导致原有实值被删除!这往往不是我们想要的。
例如:
typedef auto_ptr<class T> aptr;
aptr p(new T);
vector<aptr> vec;
vec.push_back(p);//此时p被删除,vec.at(0)拥有了原实值
vec.clear();//原实值彻底被删除
p->operation();//还想用p做啥都要崩溃了
int a=;
int *p=&a;
int *q=&a;
vector <int*> vec1,vec2;
vec1.push_back(p);
vec2.push_back(p);
vec1和vec2中都有p,也就是a的地址,但vector并没有获得a的实值的拥有权!
这里vec1和vec2消逝或者是clear都不会导致a的消亡。
容器在存入数据的时候,是存入数据值的一个拷贝,而不是存入的数据的地址。比如说对象a,
存入容器,容器有一个a的拷贝_a,那么_a和a是互相独立的。对容器内_a的操作不会影响a,以上就是
STL容器的概念和”值“的语意。
c++ STL 常用容器元素类型相关限制 指针 引用的更多相关文章
- C++ STL常用容器浅析
首先要理解什么是容器,在C++中容器被定义为:在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对象的指针,这种对象类型就叫做容器.简单来说 容器就是包含其他类的对象们的对象,当然这种(容器) ...
- 【C++】STL常用容器总结之五:双端队列deque
6.双端队列deque 所谓的deque是”double ended queue”的缩写,双端队列不论在尾部或头部插入元素,都十分迅速.而在中间插入元素则会比较费时,因为必须移动中间其他的元素.双端队 ...
- 【Example】C++ STL 常用容器概述
前排提醒: 由于 Microsoft Docs 全是机翻.所以本文表格是我人脑补翻+审校. 如果有纰漏.模糊及时评论反馈. 序列式容器 序列容器是指在逻辑上以线性排列方式存储给定类型元素的容器. 这些 ...
- C++ STL常用容器基本用法汇总
1.vector 包含头文件#include<vector> 使用命名域using namespace std 定义元素类型为T的vector vector<T> vec 增: ...
- C++中STL常用容器的优点和缺点
我们常用到的STL容器有vector.list.deque.map.multimap.set和multiset,它们究竟有何区别,各自的优缺点是什么,为了更好的扬长避短,提高程序性能,在使用之前需要我 ...
- STL常用容器使用方法
在程序头部使用#include<stack>来引入STL的stack容器,然后使用stack<int> s语句来声明一个管理整型数据的容器s.stack常用成员函数:push( ...
- C++中STL常用容器的区别(转)
我们常用到的STL容器有vector.list.deque.map.multimap.set和multiset,它们究竟有何区别,各自的优缺点是什么,为了更好的扬长避短,提高程序性能,在使用之前需要我 ...
- STL常用容器用法
-1. 本文章中所有函数原型均为C++98的标准. 通用的操作 //遍历容器--以vector,map为例 vector<int> vt; map<int,int> mp; f ...
- 转载:STL常用容器的底层数据结构实现
转载至:https://blog.csdn.net/qq_28584889/article/details/88763090 vector :底层数据结构为数组,支持快速随机访问 list:底层数据结 ...
随机推荐
- 2013杭州网赛 1001 hdu 4738 Caocao's Bridges(双连通分量割边/桥)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4738 题意:有n座岛和m条桥,每条桥上有w个兵守着,现在要派不少于守桥的士兵数的人去炸桥,只能炸一条桥 ...
- Keil MDK中单个c文件生成LIB文件
看大多数说的都是简单地将整个工程转换成.LIB,在Project->Options for Target->Output下,选择Create Library,就可以了. 不过这样生成的li ...
- springmvc+json 前后台数据交互
1. 配置(1) 文件配置参考这里(2) 导入jackson相关包:jackson-annotations-2.9.4.jar,jackson-core-2.9.4.jar,jackson-datab ...
- P2219 [HAOI2007]修筑绿化带
我是题面 这道题跟理想的正方形很像,不大明白蛤OI是怎么想的,一年出两道这么相近的题 这道题有两个矩形,所以就有了两种做法(说是两种做法,其实只是维护的矩形不同) 一种是维护大矩形,一种是维护小矩形, ...
- Linux使用技巧(一):vim中选中多行、复制和粘贴
一.选中多行: 使用命令vim打开文件,移动光标至所选行的开头,按v进入视图,键盘上按向下键,选中所需行即可. 二.复制与粘贴 三种方法: 1)在上文第一部分的基础上,按y,然后移动光标至所需粘贴处, ...
- Android Studio & eclipse 调试技巧
如上图设置多个断点,开启调试.想跨断点移动到下一个断点,点击如下图1箭头,程序将运行一个断点到下一个断点之间需要执行的代码.如果后面代码没有断点,再次点击该按钮将会执行完程序.点击箭头2指向的按钮,可 ...
- Luogu1309 瑞士轮(分治,归并排序)
Luogu1309 瑞士轮(分治,归并排序) Description 在双人对决的竞技性比赛,如乒乓球.羽毛球.国际象棋中,最常见的赛制是淘汰赛和循环赛.前者的特点是比赛场数少,每场都紧张刺激,但偶然 ...
- Spss22安装与破解步骤
Spss22安装与破解教程 向师姐请教了一些学术问题,哈哈说的有点大,不过真的很感谢,学到了很多,少走了很多弯路. 1.下载安装包 可以去IBM官网.人大论坛等网站下载,全部文件应包括spss22安装 ...
- (四)关于读文件的结束的判别方法(EOF和feof)以及区别
关于读文件的时候判断文本是否读完的方式一般可以通过EOF,一般宏定义为-1.因为ASCII码中不可能出现-1. 当以文本形式读取文件内容, 读入的字符值等于EOF时, 表示读入的已不是正常的字符而是文 ...
- 阿里云上部署了zabbix,突然无法收到报警邮件的解决办法
在阿里云上部署了zabbix,一直能正常接收到zbx发来的报警邮件(报警邮箱是163的),不知是什么原因,突然无法接收到报警邮件了. 但在服务器上手动执行echo "hello"| ...