std 里面的vector疑惑

dhy311 2002-09-13 10:21:46
本人在使用vector 数组的时候发现了一个怪现象,自己不能解释,下以下疑惑
我发现的问题可以表示成为:
当我在vector里面放有对象(在析构函数里面有delete操作数据成员)的时候,发生了程序异常,推出
具体可以看一下代码:
/***********************************************************/
#include <vector>
#include <iostream>
#include <string>
using namespace std;
class Tclass
{
private:
char *pChar;
public:
/*默认构造函数*/
Tclass()
{
pChar = NULL;
}
Tclass(char *_pChar,int length);
void display();
~Tclass();


};
Tclass::Tclass(char *_pChar,int length){
if ( _pChar == NULL ){
cout << "字符指针不能为空!"<<endl;
return;
}
else{
pChar = new char[length+1];
memset(pChar,0,length+1);
memcpy(pChar,_pChar,length);
}
}
Tclass::~Tclass()
{
if (pChar !=NULL)
delete[] pChar;
};
void Tclass::display(){
cout<<pChar<<endl;
}

void main(){
vector<Tclass> v_Tclass;
v_Tclass.clear();
for (int i =0 ;i<4; i++){
v_Tclass.push_back(Tclass("test",4));
}

vector<Tclass>::iterator p;
/*dispaly all*/

for( p = v_Tclass.begin();p!=v_Tclass.end();p++)
{
p->display();
}

};
在vc环境还是在unix g++ huanjing下都出现了程序异常退出,你可以自己在vc下面跑一下看看
...全文
84 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
stidio_zhougang 2002-09-14
  • 打赏
  • 举报
回复
完全同意楼上,因为从对象来考虑和用int什么来考虑不是一个概要。
Tommy 2002-09-14
  • 打赏
  • 举报
回复
同意Solstice(大佛)

或者不要用char*,改为boost中的shared_ptr,这样不用定义拷贝构造函数就可以实现正确的行为
陈硕 2002-09-14
  • 打赏
  • 举报
回复
data members中有pointers时,请考虑自己写copy constructor与copy assignment operator。见Effective C++ item 11
tiger28 2002-09-14
  • 打赏
  • 举报
回复
楼上说的第一次循环是对的,你在执行完push_back后,可以发现字符串确实存入了vetor中,(注意第一次执行push_back的时候vector里是空的),但随后调用destructor,pchar的内容已经没有了.

第二次循环有些不同,constructor的运行照常,进入push_back之后,这时候vector是有东西的,所以vector的实际运行是重新开辟新的区域,把原来的内容copy到新分配的空间中,然后释放原来的旧空间,问题就出在这里,vector里放的是地址的拷贝,一释放,原地址指向的内容没了,你可以调试一下,会发现第二次字符串的内容没进入vector中,和第一次是不一样的.然后程序再调用destructor,报错,因为pchar已经被释放掉了.
pi1ot 2002-09-14
  • 打赏
  • 举报
回复
好玩,这么结账,哈哈。
dhy311 2002-09-14
  • 打赏
  • 举报
回复
该问题已经结帐alexdiary() (10)tiger28(土豆) (5)
dhy311 2002-09-14
  • 打赏
  • 举报
回复
感谢alexdiary() 给我的解答,该问题已经结帐alexdiary() (10)
alexdiary 2002-09-14
  • 打赏
  • 举报
回复
不用等到退出主函数就会出错
vector为保证element的连续可能会不停的释放原来的存储区,重新分配内存
因此会频繁调用copy constructor和destructor
因为你没有定义copy constructor,所以pchar的拷贝仅仅是指针本身
另外,for循环中tclass用的是局部变量,每循环1次也要调用1次destructor

具体地说
第1次循环,push_back之前生成临时变量,调用1次constructor,然后vector分配内存并拷贝数据,调用1次copy constructor,此次循环结束,临时变量调用destructor

第2次循环,生成临时变量,调用1次constructor,然后vector释放原有存储区,调用
1次destructor,注意这个element的pchar和第1次生成的临时变量的pchar指向同一内存区,虽然已经被delete了,但是这次destructor的调用不一定会出错,因为第2次临时变量的pchar有可能也在同一地址分配内存.接着vector会为两个element
调用2次copy constructor,此次循环结束,临时变量调用destructor.
那么显然此次循环两次destructor调用总会有1次delete出错

解决办法:自定义copy constructor.
liangshulsh 2002-09-14
  • 打赏
  • 举报
回复
#include <vector>
#include <iostream>
#include <string>
using namespace std;
class Tclass
{
private:
char *pChar;
public:
/*默认构造函数*/
Tclass()
{
pChar = NULL;
}
Tclass(char *_pChar,int length);
void display();
~Tclass();


};
Tclass::Tclass(char *_pChar,int length){
if ( _pChar == NULL ){
cout << "字符指针不能为空!"<<endl;
return;//不应该有返回
}
else{
pChar = new char[length+1];
memset(pChar,0,length+1);
memcpy(pChar,_pChar,length);
}
}
Tclass::~Tclass()
{
if (pChar !=NULL)
delete[] pChar;
};
void Tclass::display(){
cout<<pChar<<endl;
}

void main(){
vector<Tclass> v_Tclass;
v_Tclass.clear();
for (int i =0 ;i<4; i++){
v_Tclass.push_back(Tclass("test",4));//"test"占五个字符,可是之分配了四个空间
}

vector<Tclass>::iterator p;
/*dispaly all*/

for( p = v_Tclass.begin();p!=v_Tclass.end();p++)
{
p->display();
}

};
onion_535 2002-09-14
  • 打赏
  • 举报
回复
我想你可以将vector定义成:vector<Tclass*>,然后没要添加一个元素,就new一个,然后将指针存入vector中。
nk_rainfall 2002-09-13
  • 打赏
  • 举报
回复
你的问题出在这里:
v_Tclass.push_back(Tclass("test",4));
在你这句代码中,先定义了一个临时变量,也就是你的Tclass("test", 4)生成的变量,我们假设他叫a, 然后你将这个临时变量push进vector, 此时的操作是:vector复制一份a放入vector中,那么此时a中的指针也被复制了,那么你申请的字符串"test"的指针,在a中存在,在vector的成员中也存在,那么当退出主函数时,问题出现了:a析构时释放了一次字符串内存,而vector析构时,他会依次调用成员的析构函数,也会释放一次字符串的内存,那么此时一块内存被充分释放了两次,就出问题了。

我没试,你可以试一下是不是这个问题!
fqcd555 2002-09-13
  • 打赏
  • 举报
回复
编译通过,link 通过,运行出问题.

69,382

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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