極客班GeekBand - C++面向對象高級開發 - 2

極客班GeekBand - C++面向對象高級開發 - 2

講師 - 侯捷

複習Complex類的實現過程

Complex.h

#ifndef __COMPLEX__
#define __COMPLEX__
#include <iostream>
using namespace std;
class complex {
private:
    double re, im;
public:
    complex(double r = 0, double i = 0) :re(r), im(i) {

    }
    complex& operator += (const complex&);
    double real() const {
        return re;
    }
    double imag() const {
        return im;
    }

    friend complex& __doapl(complex*, const complex&);
};
inline complex& complex::operator+= (const complex& r) {
    return __doapl(this, r);
}
inline complex& __doapl(complex* ths, const complex& r) {
    ths->re += r.re;
    ths->im += r.im;
    return *ths;
}
inline complex operator +(const complex& x, const complex& y) {
    return complex(x.real() + y.real(), x.imag() + y.imag());
}
inline complex operator +(const complex& x, double y) {
    return complex(x.real() + y, x.imag() + y);
}
inline complex operator +(double x, complex& y) {
    return complex(x + y.real(), y.imag());
}
ostream& operator <<(ostream& os, const complex& x) {
    os << "(" << x.real() << "," << x.imag() << ")";
    return os;
}
#endif

Complex-test.cpp

#include "Complex.h"
int main() {
    complex c1(3, 6);
    c1 += 5;
    cout << c1 << endl;
    complex c2;
    c2 = 5 + c1;
    cout << c2 << endl;
    cout << c1 << c2 << endl;
    return 0;
}

三大函數:拷貝構造,拷貝複製,析構

String.h

#include "String.h"
int main() {
    String s1;
    String s2("hello");
    String s3(s1);  //拷貝構造函數
    cout << s3 << endl;
    s3 = s2;    //拷貝賦值函數
    cout << s3 << endl;
    return 0;
}

String-test.h

#ifndef __MYSTRING__
#define __MYSTRING__
#include <iostream>
using namespace std;
#include <string.h>
class String{
public:
    String(const char* cstr);
    //class with a pointer members
    String(const String& str);
    String& operator=(const String& str);
    ~String();
    char* get_c_str() const {
        return m_data;
    }
private:
    char* m_data;
};
inline String::String(const char* cstr = 0) {
    if (cstr) {
        m_data = new char[strlen(cstr) + 1];
        strcpy(m_data, cstr);
    }
    else {
        m_data = new char[1];
        *m_data = '\0';
    }
}
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;
}
inline String::~String() {
    delete[] m_data;
}
ostream& operator<<(ostream& os, const String& str) {
    os << str.get_c_str();
    return os;
}
#endif

棧、堆與內存管理

Stack VS. Heap

Stack,是存在於某作用域(scope)的一塊內存空間(memory space)。例如當你調用函數,函數本身即會形成一個stack用來放置它所接收的參數,以及返回地址。
在函數本體(Function Body)內聲明的任何變量,其所使用的內存塊都取自上訴stack。
Heap,或稱爲system heap,是指由操作系統提供的一塊global內存空間,程序可動態分配(dynamic allocated)從某中獲得若干區塊(blocks)。

class Complex {

};

{
    Complex c1(1, 2);   //c1所佔用的空間來自stack
    Complex* p = new Complex(3);    //Complex(3)是個臨時變量,所佔用的空間是以new動態分配而得,並由p指向。佔用空間來自heap。
}

stack objects、static local objects、global objects的生命期

class Complex {

};
Complex c3(1, 2);

{
    Complex c1(1, 2);
    static Complex c2(1, 2);
}
int main() {

}
  • c1便是所謂stack object,其生命在作用域(scope)結束之際介紹。這種作用域內的object,又稱爲auto objects,因爲它會被”自動“清理。
  • c2便是所謂static object,其生命在作用域(scope)結束之後仍然存在,直到整個程序結束。
  • c3便是所謂global object,其生命在整個程序結束之後才結束。你也可以把它視爲一種static object,其作用域是整個程序。

heap objects的生命週期

class Complex {

};

{
    Complex* p = new Complex;
    delete p;
}
  • p所指的便是heap object,其生命在它被delete之際結束。
class Complex {

};

{
    Complex* p = new Complex;
}
  • 以上出現內存泄露(memory leak),因爲當作用域結束,p所指的heap object仍然存在,但指針p的生命卻結束了,作用域之外再也看不見p(也就沒有機會delete p)

new:先分配memory,再調用ctor

Complex* pc = new Complex(1, 2);

編譯器轉化爲:

Complex* pc;

void* mem = operator new(sizeof(Complex));  //分配內存,內部調用malloc(n)
pc = static_cast<Complex*>(mem);    //轉型
pc->Complex::Complex(1, 2); //構造函數

delete:先調用dtor,在釋放memory

String* ps = new String("Hello");
delete ps;

編譯器轉化爲:

String::~String(ps);   //析構函數
operator delete(ps);    //釋放內存,內部調用free(ps)

動態分配所得內存塊(memory block),in VC

動態分配所得的array

以上兩部分略,這兩部分侯捷老師主要爲說明的是delete和delete[]的區別。其實就是,開闢的數組就用delete[],否則可能會內存泄露,爲什麼是可能?因爲:

int* p = new int[1];

複習String類的實現過程

略,同三大函數:拷貝構造,拷貝複製,析構部分。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章