[C++]千万小心局部变量
2004-07-08 21:02
369 查看
千万小心局部变量
小心看好你的局部变量,尤其在这种情况下:
当你在一个function中声明了一个对象,然后你不遗余力地在对这个对象进行加工、进行操作,辛苦半天将他作为结果传出。好,编译,没问题,你似乎心满意足。可是别高兴太早,运行一下试试,哦,my god,内存引用错误,操作系统奉上了个无比可爱的小红叉叉,可是你却恨不得把他“一百遍”了。你有过这种经历吗?恩,好,让我们看看下面这段足以产生这样效果的代码:
#include <iostream>
#include <cstring>
using namespace std;
class String
{
public:
String()
{
}
String(char* str)
{
size_t len = strlen(str);
p = new char[len + 1];
strcpy(p,str);
}
String(const String& rhs)
{
size_t len = strlen(rhs.p);
p = new char[len + 1];
strcpy(p,rhs.p);
}
void print()
{
char* pp = p;
while(*pp != '/0')
{
cout << *pp;
++pp;
}
}
char* p;
};
int main()
{
String str1("Hello,world!/n");
String str2(str1);
str1.print();
str2.print();
return 0;
}
恩~,程序模拟了string的行为,很简单不是吗?运行一下,似乎跑得不错啊。好,我现在想这样操作我的string:
String str3;
str3 = str1 + str2;
怎么办?很自然的想法就是为我的程序添加一个对运算符“+”的重载函数。这样写,看有问题吗:
String operator +(const String& rhs)
{
String temp;
size_t len = strlen(p) + strlen(rhs.p);
temp.p = new char[len];
strcpy(temp.p,p);
strcat(temp.p,rhs.p);
return temp;
}
将下面的main替换掉原来的main函数:
int main()
{
String str1("Hello,world!");
String str2(str1);
String str3;
str3 = str1 + str2;?
cout << "/nstr1: ";
str1.print();
cout << "/nstr2: ";
str2.print();
cout << "/nstr3: ";
str3.print();
cout << endl;
return 0;
}
运行一下,好,没问题!下面我们来回顾一下我们的程序,什么?你是不是发现我们自己在堆上new出来的内存用完后都没释放呢!这怎么能行?!于是,很自然地,我们为我们的程序添加了一个析构函数:
~String()
{
delete[] p;
}
编译……,OK!没问题!
运行……,oh god!怎么了?小红叉叉!!!
我在文中开始的时候所描述的一幕终于发生了,是不是期待已久啊。呵呵,你可能已经发现了,问题就在+操作符重载函数里面,因为他返回了一个局部变量。当这个局部变量被传出去后,在+操作符重载函数的他本身就销毁了。所以可以判断这个赋值号“=”并没有把对象中的内容一一拷贝给目标。所以,一种办法是重载一下“=”,而另一种更简单的方法便是将str3声明为:String str3 = str1 + str2;从而直接利用拷贝构造函数完成这个任务,试试看,程序是不是又能跑了?下面我们来看看另一种解决方案,我们来重载一下“=”,我们为我们的程序中添加下面的代码:
void operator =(const String& rhs)
{
size_t len = strlen(rhs.p);
p = new char[len + 1];
strcpy(p,rhs.p);
}
编译运行一下看看,呵呵,我们的程序又恢复了活力!
所以,我们看到,在一个function中返回一个局部变量,他会在他本身被销毁之前copy自身,从而将内容赋给目标。因此,你需要重载"="并提供拷贝构造函数;而如果你试图在一个function中返回一个局部变量的指针,那你麻烦大了。这个指针在他本身被销毁之前copy自身(注意这是个地址信息),然而目标再次想访问他的时候,他的原来那份地址已经被销毁了,我们的目标并没有得到他的具体信息,我们当时得到的仅仅是他的一个地址信息而已。重点是:pass-by-value便是调用copy constructor的同意词;initialization初始化是由constructor完成,而assignment赋值是由operator=完成。所以,到此为止,一切都清净了...
9fed
小的菜鸟一只,不知天高地厚,发拙作于此,欢迎各位达人拍砖!
sun
2004-7-15
小心看好你的局部变量,尤其在这种情况下:
当你在一个function中声明了一个对象,然后你不遗余力地在对这个对象进行加工、进行操作,辛苦半天将他作为结果传出。好,编译,没问题,你似乎心满意足。可是别高兴太早,运行一下试试,哦,my god,内存引用错误,操作系统奉上了个无比可爱的小红叉叉,可是你却恨不得把他“一百遍”了。你有过这种经历吗?恩,好,让我们看看下面这段足以产生这样效果的代码:
#include <iostream>
#include <cstring>
using namespace std;
class String
{
public:
String()
{
}
String(char* str)
{
size_t len = strlen(str);
p = new char[len + 1];
strcpy(p,str);
}
String(const String& rhs)
{
size_t len = strlen(rhs.p);
p = new char[len + 1];
strcpy(p,rhs.p);
}
void print()
{
char* pp = p;
while(*pp != '/0')
{
cout << *pp;
++pp;
}
}
char* p;
};
int main()
{
String str1("Hello,world!/n");
String str2(str1);
str1.print();
str2.print();
return 0;
}
恩~,程序模拟了string的行为,很简单不是吗?运行一下,似乎跑得不错啊。好,我现在想这样操作我的string:
String str3;
str3 = str1 + str2;
怎么办?很自然的想法就是为我的程序添加一个对运算符“+”的重载函数。这样写,看有问题吗:
String operator +(const String& rhs)
{
String temp;
size_t len = strlen(p) + strlen(rhs.p);
temp.p = new char[len];
strcpy(temp.p,p);
strcat(temp.p,rhs.p);
return temp;
}
将下面的main替换掉原来的main函数:
int main()
{
String str1("Hello,world!");
String str2(str1);
String str3;
str3 = str1 + str2;?
cout << "/nstr1: ";
str1.print();
cout << "/nstr2: ";
str2.print();
cout << "/nstr3: ";
str3.print();
cout << endl;
return 0;
}
运行一下,好,没问题!下面我们来回顾一下我们的程序,什么?你是不是发现我们自己在堆上new出来的内存用完后都没释放呢!这怎么能行?!于是,很自然地,我们为我们的程序添加了一个析构函数:
~String()
{
delete[] p;
}
编译……,OK!没问题!
运行……,oh god!怎么了?小红叉叉!!!
我在文中开始的时候所描述的一幕终于发生了,是不是期待已久啊。呵呵,你可能已经发现了,问题就在+操作符重载函数里面,因为他返回了一个局部变量。当这个局部变量被传出去后,在+操作符重载函数的他本身就销毁了。所以可以判断这个赋值号“=”并没有把对象中的内容一一拷贝给目标。所以,一种办法是重载一下“=”,而另一种更简单的方法便是将str3声明为:String str3 = str1 + str2;从而直接利用拷贝构造函数完成这个任务,试试看,程序是不是又能跑了?下面我们来看看另一种解决方案,我们来重载一下“=”,我们为我们的程序中添加下面的代码:
void operator =(const String& rhs)
{
size_t len = strlen(rhs.p);
p = new char[len + 1];
strcpy(p,rhs.p);
}
编译运行一下看看,呵呵,我们的程序又恢复了活力!
所以,我们看到,在一个function中返回一个局部变量,他会在他本身被销毁之前copy自身,从而将内容赋给目标。因此,你需要重载"="并提供拷贝构造函数;而如果你试图在一个function中返回一个局部变量的指针,那你麻烦大了。这个指针在他本身被销毁之前copy自身(注意这是个地址信息),然而目标再次想访问他的时候,他的原来那份地址已经被销毁了,我们的目标并没有得到他的具体信息,我们当时得到的仅仅是他的一个地址信息而已。重点是:pass-by-value便是调用copy constructor的同意词;initialization初始化是由constructor完成,而assignment赋值是由operator=完成。所以,到此为止,一切都清净了...
9fed
小的菜鸟一只,不知天高地厚,发拙作于此,欢迎各位达人拍砖!
sun
2004-7-15
相关文章推荐
- 关于C++中的局部变量
- c++ 返回对象的引用要小心
- C++的那些秘密---函数返回局部变量
- 对“C++添加一个头文件和extern以及全局变量和局部变量问题”的解释
- c++ 全局变量、局部变量、静态全局变量、静态局部变量的区别
- C/C++:在函数外存取局部变量的一个比喻
- c++返回局部变量的指针
- C/C++全局变量和局部变量重名问题
- c++ - 小心从派生类到基类的转换 (ptr Vs. obj)
- C|C++中的静态全局变量,静态局部变量,全局变量,局部变量的区别
- C++关于不能返回局部变量的指针的研究
- C++编程经验-返回局部变量的讨论
- 我学习C++:无题(每日追加型,小心爆了:酱爆)(一)
- C++里类中定义对象与定义局部变量的问题
- 千万要小心我们的程序员~!
- C|C++中的静态全局变量,静态局部变量,全局变量,局部变量的区别
- 【C++】小心使用文件读写模式:回车('\r') 换行('\n')问题的一次纠结经历
- C|C++中的静态全局变量,静态局部变量,全局变量,局部变量的区别
- C++反汇编九(全局变量与局部变量)
- c++面试题之千万别闲着