在这个类得设计和实现中,动态内存的分配和回收是一个关键的设计部分,稍有不慎,就可能造成内存泄露,当程序的运行次数上升到一定程度,内存的使用率也就越来越高,所以在关键的每一步恰当的分配和回收内存是这个类成功的关键。

      那么类得内存占用到底是怎么分配的呢?    

      静态成员变量:一般存放在另外一块内存区域,一个类只有一个静态成员副本,所以的对象一起共享它。

      每初始化一个对象,那么都会为它分配数据成员所要占用的内存空间。那么在MyString类中,我们也只是为string分配了可以存储指针的地址,并没有分配存储具体的字符串的地址。

      

   1.那么构造函数在初始化一个类对象时,必须使用new为对象分配存储字符串的内存空间,这个就是我们的动态内存分配。但是每一个new分配的内存空间必须通过delete来释放,我们一般通过析构函数来实现:

     构造函数的动态内存分配:

MyString::MyString()
{
	length = 0;
	string = new char;
	char *s = "/0";
	memcpy(string,s,1);
    ++string_number;
}

MyString::MyString(const char*str)
{
    length = strlen(str);
    string = new char(length+1);
    memcpy(string,s,length);
    ++string_number;
}
MyString::MyString(MyString &str)
{
	length = str.length;
	string = str.string;
	++string_number;
}

   析构函数的内存释放:

MyString::~MyString()
{
	delete[]string;
	--string_number;
}

  2.那么在一个对象的使用过程中,通过调用其他的方法函数也会进行相应的内存的释放和重新分配:

MyString &MyString::operator+=(const MyString&str)
{
     char *dest;
     dest = new char[str.length+length+1];
     memcpy(dest,string,length);
     memcpy(dest+length,str.string,str.length+1);
     delete[]string;
     string = dest;
     return *this;
}
MyString &MyString::operator=(const MyString&str)
{
   if(&str == this)
	   return *this;
   delete[]string;
   string = new char[str.length];
   length = str.length;
   return *this;
}

     如上在这两个函数中,返回的对象和原来对象的字符串长度不同,那么我们就必须先释放原来的内存空间,然后让字符串指针指向合适长度的一块新的内存空间进行返回。

     注意:当重新定位字符串指针定位时,必须先释放原来的内存。

      同时在第二个赋值运算中,不能直接通过指针赋值来返回:

delete[]string;
      string = str.string;
      return *this;

     这样的话调用对象的string和str.string指向同一块内存区域,任何一个对像先退出调用析构函数以后,当第二个对象再调用析构函数时,这个容易引起同一块内存的两次释放,引起错误

 

   总结:

   容易涉及到内存动态分配的方法函数:

   1.构造函数和析构函数

   2.赋值函数(常量或者对象),运算符重载函数