用指针不错,总不能一个个保存吧
构造函数接受的参数是自己这个类的对象(引用),为拷贝构造。
=
重载,参数是自己这个类的对象,为拷贝复制。
String(const String& str); String& operator=(const String& str); inline String::String(const String& str) { m_data = new char[ strlen(str.m_data) + 1 ]; strcpy(m_data, str.m_data); } inline String& String::operator=(const String& str) { if (this == &str) return *this;//检测自我赋值,一定要 delete[] m_data;//先清空 m_data = new char[ strlen(str.m_data) + 1 ];//分配一样的空间 strcpy(m_data, str.m_data);//拷贝 return *this; } String s1("hello"); String s2(s1); String s2=s1;//与上一行一个意思,看函数实现也差不多
只要写的是带指针的类,就必须完成这两个函数。对于不带指针的类complex,不写也一样,编译器会忠实的完全bit复制过来,已经很好了。但是指针不能复制,空间应该重新分配。
浅拷贝就是纯bit复制,造成内存泄露和别名alias;深拷贝就是把指针指的内容重新创建并赋值。
这里的构造函数,拿到外部去实现了。
String(const char* cstr=0); #include <cstring> inline String::String(const char* cstr) { if (cstr) { m_data = new char[strlen(cstr)+1]; strcpy(m_data, cstr); } else { //未指定初值 m_data = new char[1]; *m_data = '\0'; } } String* p=new String(“hello”)
写法类似构造函数,与类同名,且前方有个 ~
.
~String(); inline String::~String() { delete[] m_data; }
当这个类的对象死亡时、离开作用域时,会被调用(自动)。
有指针的类,要做析构函数处理动态分配的空间(手动)。
用指针动态分配的对象,也要手动delete。
要写成全局函数,
#include <iostream> using namespace std; ostream& operator<<(ostream& os, const String& str) { os << str.get_c_str(); return os; } char* get_c_str() const {return m_data;}//写到类里面
栈是存在于一个函数作用域的一块内存空间,用于存放参数、返回地址等。
堆是由操作系统提供的一块全局内存空间,程序可以动态分配从其中获得一定的大小。
Complex c1(1,2); Complex* c2=new Complex(2,3);
栈里的内容,函数结束后(离开作用域)就会被释放。会调用析构函数。又称为 auto object
,因为会自动释放。
如果是 static object
,直到整个程序结束后才会释放。
如果是 global object
,有点类似static,也是程序结束才会释放。
堆里的内容,必须手动释放。一个new对应一个delete,其生命在delete后结束。如果不释放,会内存泄露,其严重性在于:当作用域结束后,指针的生命结束了,作用域之外没办法使用指针,对这一块的内存就失去了控制。
new
是先分配memory,再调用构造函数ctor。可以分为下述步骤:
Complex* pc=new Complex(1,2); Complex* pc; void mem=operator new(sizeof(Complex));//operator new其实是一个名字特别的函数,下一层就是malloc。 pc=static_cast<Complex*>(mem);//指针的类型转换 pc->Complex::Complex(1,2);//构造函数
构造函数是个成员函数,现在是由指针调用,因此相当于指针是构造函数里的 this
,指向内存空间的起点。然后调用构造函数复制。
delete
是先调用析构函数的dtor,再释放memory。
String* ps = new String("Hello"); delete ps; String::~String(ps);//释放字符串里面的动态分配的空间 operator delete(ps);//下一层是free
vc给分配的内存空间一定是16B的倍数。
在debug下。会包含很多调试信息,以及cookie(用于记录长度和分配状况,提供给malloc和free用)。还可能有补充为16B整数倍的padding。
在release下,没有调试信息,别的一样。
要互相搭配,否则会出错。写法如下:
m_data = new char[strlen(cstr)+1]; delete[] m_data;
动态分配的数组中,在数据前会有一个整数记录数组容量。(VC)具体问题如下:
删除整个数组没问题,因为大小写在cookie里;但是除了第0个元素,后面的元素的没有调用析构函数,这就造成了内存泄露。(当然是因为后面类的变量有指针)