STL容器对元素的要求?越看越糊涂!

papaofdoudou
人工智能领域新星创作者
博客专家认证
2009-05-26 08:49:45
请教各位朋友,我在看林越的 高质量C++三版时遇到一个问题一直不能理解,描述如下:
“智能指针式一种模拟原始指针行为的对象,因此理论上也可以作为容器的元素,就像原始指针可以作为容器的元素一样,但是智能指针毕竟是一种特殊的对象,它们在原始指针共享实值对象的基础上普遍增加了自动销毁实值对象的能力,而且其实现方式和种类都非常多,如果不分好坏的都将他们作为容器的元素,可能导致容器之间共享元素对象实值,这不仅不符合STL容器的概念和”值“的语意,而且会存在安全隐患,同时也会存在许多应用上的限制,特别是像STL中的auto_ptr这样的智能指针。”
看了上面的话我疑惑重重,首先,承认2点:
1.原始指针共享实值对象,例如int a=5; int*p=&a; int*q=&a; p和q共享了实值对象a;

2.原始指针可以作为容器的元素。例如vector<int*>vec.vec.push_back(p),vec.push_back(q);p和q指向同一个实值对象a,但是可以把他们放到一个向量里?

上面两点在文中是前提,但是看下面:

"导致容器之间共享元素对象实值,这不仅不符合STL容器的概念和”值“的语意......"
前面明明已经说了,可以将共享实值对象的原始指针作为容器元素,但是这句话又说为了满足“STL容器的概念和”值“的语意”,容器之间不能共享实值。当然也就不能把原始指针放进去了,因为原始指针共享了实值对象。
为什么前后自相矛盾??
到底“STL容器的概念和”值“的语意"是指的什么?
int a=5;
int *p=&a;
int *q=&a;
vector<int*> vec1,vec2;
vec1.push_back(p);
vec2.push_back(p);
容器vec1和容器vec2都包含了p,这是不是不符合”STL容器的概念和”值“的语意”?因为vec1和vec2共享了实值对象a??
迷惑死了~!!!
哪位大虾帮忙解惑,感激不尽!!!!
...全文
599 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
crst_zh 2009-05-26
  • 打赏
  • 举报
回复
对于auto_ptr要牢记:
所有权的转移,任何时候有且仅有一个auto_ptr拥有对象的所有权,

那么试想一下,定义一个vector,内部是auto_ptr,它的迭代器就不能用。
  • 打赏
  • 举报
回复
不错的贴,收藏
wangpingfang 2009-05-26
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 beyond071 的回复:]
C/C++ code原始指针共享实值对象的基础上普遍增加了自动销毁实值对象的能力


auto_ptr这种智能指针的特性,决定了它不适合作为容器的元素的。比如用于vector时,使用push_back(),调用的是复制构造函数。
但auto_ptr在拷贝构造的同时,把原有对象的实值拥有权转给了vector,同时删除了原有的auto_ptr。可能会导致后面使用中的错误。
当使用vector.clear()或者这个vector的生存周期到了,被释放的时候,同时会导致原有实值…
[/Quote]
讲得很好。
pathuang68 2009-05-26
  • 打赏
  • 举报
回复
leegongbo 2009-05-26
  • 打赏
  • 举报
回复
学习了。我在14楼的回复可以忽略。原来push_back()函数直接会调用拷贝构造。。。。


[Quote=引用 11 楼 beyond071 的回复:]
C/C++ code原始指针共享实值对象的基础上普遍增加了自动销毁实值对象的能力


auto_ptr这种智能指针的特性,决定了它不适合作为容器的元素的。比如用于vector时,使用push_back(),调用的是复制构造函数。
但auto_ptr在拷贝构造的同时,把原有对象的实值拥有权转给了vector,同时删除了原有的auto_ptr。可能会导致后面使用中的错误。
当使用vector.clear()或者这个vector的生存周期到了,被释放的时候,同时会导致原有实值…
[/Quote]
adventurelw 2009-05-26
  • 打赏
  • 举报
回复
智能指针auto_ptr的设计是不共享实值,按道理主要出问题是在容器之间复制构造时,因为
容器之间的复制构造表现是结束后两边的值相等,但auto_ptr不能共享实值,必有一个是空
的。
leegongbo 2009-05-26
  • 打赏
  • 举报
回复
1楼说的很有道理了。

智能指针它们在原始指针共享实值对象的基础上普遍增加了自动销毁实值对象的能力。这句很重要。

容器的本身是用来保存数据的,如果容器本身没有删除操作及撤消操作,元素无故的消失了或者对元素

的操作导致未定义现象,那就有背容器的设计目的。如果智能指针作为容器的元素的话,请看下面例子:
int a =10;
int *p = &a;
auto_ptr<int> ptr( p);
vector< auto_ptr<int> > vector;
vector.push_back(ptr); //假设ptr是vector第一个元素。
auto_ptr<int> ptr1 = vector[0]; //取刚才存的ptr赋值给 prt1;这个操作使直接把指针p的所有权完全交给了prt1,而ptr不再拥有对
//p的所有权。因此在程序的后面,如果再使用容器取得ptr,那对它的操作就未定义了。这样的容器已被
//破坏了。
vector.push_back(ptr);
vector< auto_ptr<int> > vector2;
vector2.push_back(p); //如果让vector与vector2同时保存ptr智能指针。当其中一个vector撤消后,ptr已被释构,再使用另一个
//vector时,就有隐患了。

个人理解,如有误请高手指正。


[Quote=引用 1 楼 adventurelw 的回复:]
人家说了,不要部分好坏地把智能指针作为容器的元素,你硬要那样做的话,别人是没有办法的
容器元素比如vector对元素对象的唯一要求是可以复制构造。
但比如说你把auto_ptr对象用作了容器元素,虽然其也可以复制构造,只不过复制构造会破坏原始对象,你用了之后会导致未定义现象。
你也可以不伽原始指针用作容器对象,但如果涉及到动态内存分配而程序设计并没有解决这个问题的话,容器本身不会帮你解决,他也不拒绝你的

[/Quote]
dingdingko 2009-05-26
  • 打赏
  • 举报
回复
我一直是这么理解的!申明一下从STL源码剖析中看来的!
由于vector是一个动态数组,当数据大于其申明的大小时会自动分配原来两倍的空间,然后
从新拷贝原来的指针,用了智能指针后很有可以在这个环节出错问题!就像含有指针的类做
拷贝时会出现深浅拷贝问题一样!
个人理解!
adventurelw 2009-05-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 adventurelw 的回复:]
人家说了,不要部分好坏地把智能指针作为容器的元素,你硬要那样做的话,别人是没有办法的
容器元素比如vector对元素对象的唯一要求是可以复制构造。
但比如说你把auto_ptr对象用作了容器元素,虽然其也可以复制构造,只不过复制构造会破坏原始对象,你用了之后会导致未定义现象。
你也可以不伽原始指针用作容器对象,但如果涉及到动态内存分配而程序设计并没有解决这个问题的话,容器本身不会帮你解决,他也不拒绝你的
使用…
[/Quote]
恩,这里说错了一点
auto_ptr不能作为容器元素是通过设计上限定了的。因为编译不能通过……但C++标准库里对这一点的介绍时
仍然说了:这也是有可能通过编译的,所以你不要那样做!
beyond071 2009-05-26
  • 打赏
  • 举报
回复
原始指针共享实值对象的基础上普遍增加了自动销毁实值对象的能力

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=5; 
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的消亡。
iambic 2009-05-26
  • 打赏
  • 举报
回复
通俗点吧:值语意就是像int一样可以随便复制的,不需要像指针一样手动释放资源。
dingdingko 2009-05-26
  • 打赏
  • 举报
回复
侯哥的STL源码剖析里也有类试的话,smart_point可惜我也一头雾水!
不过顶起!
lpf000 2009-05-26
  • 打赏
  • 举报
回复
"导致容器之间共享元素对象实值,这不仅不符合STL容器的概念和”值“的语意......"
如果不分好坏的都将他们作为容器的元素
就是说乱用智能指针或其他指针作为容器元素,有可能2个元素指向同一个对象,2个元素(指针)对应一个对象,甚至更多,
"值"的语义就是 每个元素都应该是单独的完整的元素,而其元素指针共享同一对象,导致操作一个元素而影响其他元素影响整个容器。。。
goodname 2009-05-26
  • 打赏
  • 举报
回复
回头看了一下,再修改一下3楼的一句,没说很清楚。

如果同时存在两个vector,都执行如上的操作的时候,
其中一个vector对旧元素执行了析构,而另外一个vector对同一个元素进行析构的时候,就出问题了。


对于你举的例子没有这样的问题,这是因为对于char*执行的值拷贝,而且也没有析构函数。
fairchild811 2009-05-26
  • 打赏
  • 举报
回复
重复析构了
基本类型是没问题的
机智的呆呆 2009-05-26
  • 打赏
  • 举报
回复
个人认为,容器在存入数据的时候,是存入数据值的一个拷贝,而不是存入的数据的地址。比如说对象a,
存入容器,容器有一个a的拷贝_a,那么_a和a是互相独立的。对容器内_a的操作不会影响a,以上就是
STL容器的概念和”值“的语意。而智能指针在存入容器时,比如auto_ptr在拷贝的过程中,会使先前的指针
丧失所有权(值为null了),因为修改了要存入数据的值,也就是说auto_ptr共享元素对象实值了。
taodm 2009-05-26
  • 打赏
  • 举报
回复
换本好点的书看看呗。
比如《effective stl》《STL.Tutorial.and.Reference.Guide》《The C++ Standard Library》。。。。
yshuise 2009-05-26
  • 打赏
  • 举报
回复
所谓的“值语义”就是说可不可以拷贝的问题。
auto_ptr不满足这个条件。
goodname 2009-05-26
  • 打赏
  • 举报
回复
容器的大小是可以改变的,而且往往会自动改变。
对于vector来说,如果空间不够了,会自动增长,但是如果原来所在的空间不够的话,系统就会在另外一个地方分配一个满足需要的空间。
所以在此时,对于vector已有的元素也进行了移动,此时就会执行新的构造函数,同样还会把原来位置的旧元素析构掉。

如果同时存在两个vector,其中一个对旧元素执行了析构,会导致另外一个对同一个元素析构,这样就会出问题。

对于你举的例子没有这样的问题,这是因为对于char*执行的值拷贝。
huizhouxueyuan 2009-05-26
  • 打赏
  • 举报
回复
这个```要怎么说好呢``` 感觉有好多东西要说```
加载更多回复(8)

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧