初始化和赋值的一些问题
2005-01-05 18:59
309 查看
初始化和赋值的一些问题
fancy于2005年1月5日
C++的神奇之处就是无论你怎样费劲心机的构思一个类,结果却还是有这样那样的缺陷和错误。
首先让我们明确一下初始化和赋值的区别。对于c++来说,一个新的对象被创建,就有初始化操作出现;赋值则是修改一个已经被创建的对象的值,这个时候并没有新的对象被创建。
EString p=q;//初始化,新对象p被创建
p=q;// //赋值,已存在的对象p的值被改变
初始化由构造函数实现,赋值由operator=操作符实现。
构造函数中有两个容易迷惑的概念:“缺省构造函数”和“缺省的复制构造函数”。前者是不需要任何参数就可以被调用的构造函数;后者是由编译器自动生成的复制构造函数,如果我们没有为类声明一个复制构造函数,那么编译器会自动生成一个。
我们自己在编写一个类的时候,经常会遇到缺省的复制构造函数的行为和我们的期望值不相符。
请看以下这段程序,一个字符串类。
class EString
{
private:
char *pstr
public:
EString(const char *str="");
virtual ~EString();
void Release()
};
EString::EString(const char *str)
{
pstr=new char[strlen(str)+1];
strcpy(pstr,str);
}
EString::~EString()
{
if(!pstr)
delete[] pstr;
}
void EString::Release()
{
delete[] pstr;
}
上面的EString类中,EString类的缺省复制构造函数会把pstr这个指针进行复制。如果我进行了如下的操作:
EString p("hello");
EString q=p;
p.Release();
那么对象q中的pstr就会指向被释放的内存,原因是p和q中的pstr实际上都指向同一块内存区域。这是一个非常严重的问题,因此我们必须改进这个类的设计,确保每一个对象都有一份自己独立的数据拷贝。
于是我们需要自己来声明一个复制构造函数:
class EString
{
private:
char *pstr
public:
EString(const char *str="");
virtual ~EString();
EString(const EString& s);
void Release()
};
EString::EString(const char *str)
{
pstr=new char[strlen(str)+1];
strcpy(pstr,str);
}
EString::~EString()
{
if(!pstr)
delete[] pstr;
}
EString::EString(const EString& s)
{
pstr=new char[strlen(s.pstr)+1];
strcpy(pstr,s.pstr);
}
void EString::Release()
{
delete[] pstr;
}
通过上边的代码,实现自己的复制构造函数,这样每一个对象都能拥有一份数据私有拷贝了。
在解决缺省复制构造函数的问题之后,我们理所当然的想到,缺省的赋值操作符也会存在同样的问题。
我们执行下面的代码:
EString p("hello");
EString q;
q=p;
p.Release();
先前缺省复制构造函数出现的问题,又出现在赋值操作符之中了。同样我们需要自己来重载赋值运算符。
const EString& EString::operator =(const EString &s)
{
if(pstr!=s.pstr)
{
delete [] pstr;
pstr=new char[strlen(s.pstr)+1];
strcpy(pstr,s.pstr);
}
return *this;
}
重载赋值运算符之后,就可以避免指针指向同一块内存区域,让每个对象具有自己独立的数据了。
总的来说,我们在对待那些有指针的类的时候需要格外注意,对于它们来说缺省的复制构造函数和缺省的赋值操作符可能是不恰当的,它们只是简单地复制了指针而不是指针所指向那的那些重要的数据。这是最近所考虑到的一些问题,希望能给各位一些小小帮助。
fancy于2005年1月5日
C++的神奇之处就是无论你怎样费劲心机的构思一个类,结果却还是有这样那样的缺陷和错误。
首先让我们明确一下初始化和赋值的区别。对于c++来说,一个新的对象被创建,就有初始化操作出现;赋值则是修改一个已经被创建的对象的值,这个时候并没有新的对象被创建。
EString p=q;//初始化,新对象p被创建
p=q;// //赋值,已存在的对象p的值被改变
初始化由构造函数实现,赋值由operator=操作符实现。
构造函数中有两个容易迷惑的概念:“缺省构造函数”和“缺省的复制构造函数”。前者是不需要任何参数就可以被调用的构造函数;后者是由编译器自动生成的复制构造函数,如果我们没有为类声明一个复制构造函数,那么编译器会自动生成一个。
我们自己在编写一个类的时候,经常会遇到缺省的复制构造函数的行为和我们的期望值不相符。
请看以下这段程序,一个字符串类。
class EString
{
private:
char *pstr
public:
EString(const char *str="");
virtual ~EString();
void Release()
};
EString::EString(const char *str)
{
pstr=new char[strlen(str)+1];
strcpy(pstr,str);
}
EString::~EString()
{
if(!pstr)
delete[] pstr;
}
void EString::Release()
{
delete[] pstr;
}
上面的EString类中,EString类的缺省复制构造函数会把pstr这个指针进行复制。如果我进行了如下的操作:
EString p("hello");
EString q=p;
p.Release();
那么对象q中的pstr就会指向被释放的内存,原因是p和q中的pstr实际上都指向同一块内存区域。这是一个非常严重的问题,因此我们必须改进这个类的设计,确保每一个对象都有一份自己独立的数据拷贝。
于是我们需要自己来声明一个复制构造函数:
class EString
{
private:
char *pstr
public:
EString(const char *str="");
virtual ~EString();
EString(const EString& s);
void Release()
};
EString::EString(const char *str)
{
pstr=new char[strlen(str)+1];
strcpy(pstr,str);
}
EString::~EString()
{
if(!pstr)
delete[] pstr;
}
EString::EString(const EString& s)
{
pstr=new char[strlen(s.pstr)+1];
strcpy(pstr,s.pstr);
}
void EString::Release()
{
delete[] pstr;
}
通过上边的代码,实现自己的复制构造函数,这样每一个对象都能拥有一份数据私有拷贝了。
在解决缺省复制构造函数的问题之后,我们理所当然的想到,缺省的赋值操作符也会存在同样的问题。
我们执行下面的代码:
EString p("hello");
EString q;
q=p;
p.Release();
先前缺省复制构造函数出现的问题,又出现在赋值操作符之中了。同样我们需要自己来重载赋值运算符。
const EString& EString::operator =(const EString &s)
{
if(pstr!=s.pstr)
{
delete [] pstr;
pstr=new char[strlen(s.pstr)+1];
strcpy(pstr,s.pstr);
}
return *this;
}
重载赋值运算符之后,就可以避免指针指向同一块内存区域,让每个对象具有自己独立的数据了。
总的来说,我们在对待那些有指针的类的时候需要格外注意,对于它们来说缺省的复制构造函数和缺省的赋值操作符可能是不恰当的,它们只是简单地复制了指针而不是指针所指向那的那些重要的数据。这是最近所考虑到的一些问题,希望能给各位一些小小帮助。
相关文章推荐
- linux yum安装mysql后要注意的一些初始化问题
- List初始化赋值问题
- 关于list的的一些问题(未初始化)
- 还是毕业设计的问题,Delphi中ADO数据库组件的TParameter&TParameters的问题,看了一些书上很少讲ADOQuery组件参数的赋值问题所以在这里提一下,希望对一些人有帮助
- 数组初始化与赋值注意的问题
- 浅谈JavaScript的赋值操作的一些问题
- python多维数组初始化后赋值的问题
- ios关于viewController初始化赋值的问题,VC调用问题
- Viewpager + fragment,其中一些fragment不被保存在内存,切换导致初始化问题
- Android编程心得---ViewPager+Fragment篇(一)初始化ViewPager的一些问题
- 关于初始化 degug 和Release 的一些相关问题
- DateRangePicker 中文化以及老版本的一些初始化问题,不能选择秒的问题
- 基于ARM硬件初始化的一些细节问题的解释
- scut协议配置工具初始化的一些问题
- 初始化的一些问题(Vector使用)
- 解决C++全局变量只能初始化不能赋值的问题
- 对象的初始化的一些问题
- Java集合初始化赋值等相关问题
- c语言中整数赋值和字符赋值的一些问题
- ARM平台C语言库初始化的一些问题。(摘录)