13章,拷貝控制

13.1,拷貝、賦值與銷燬


13.1.1拷貝構造函數

  • 直接初始化與拷貝初始化的區別:直接初始化使用函數匹配,拷貝初始化是將右側對象拷貝到正在創建的對象中

  • A(const A&)


EX1

1,拷貝構造函數的定義:

一個構造函數的第一個參數是自身類型的引用,且任何額外參數都有默認值。

2,出現場合:

  • 用“=”定義變量,
  • 將一個對象作爲實參傳遞給一個非引用類型的形參,
  • 從一個返回類型爲非引用類型的函數返回一個對象
  • 花括號{} 初始化

EX2 :

拷貝構造函數自己的參數必須是引用類型。

因爲如果不是的話,在調用拷貝構造函數時,將一個對象作爲實參傳遞給一個非引用類型的形參時,會再次調用該拷貝構造函數陷入死循環。


EX5

HasPtr(const string &Hp){
    //*ps = *Hp.ps; 會執行出錯
    ps = new string(*Hp.ps)
    i = Hp.i;
}


13.1.2,拷貝賦值運算符

一般拷貝賦值運算符組合了析構函數和構造函數的工作:好的使用方法是:先將右側運算對象特殊成員(如指針)保存到局部臨時變量中,然後銷燬左側運算對象的需要顯示銷燬的成員(如指針)(爲了防止自賦值,先後順序不能變),再將臨時對象賦值。(參考ex22)

  • A& operator=(const A&)

EX6

作用:控制對象的賦值.。注意:返回值爲左側運算對象的引用。


EX7 ???


EX8



13.1.3 析構函數


指向一個對象的指針或引用離開作用域時,析構函數不會執行


EX9

作用:釋放對象使用的資源,並銷燬對象的非static數據成員


EX10 ???


EX11

~HasPtr(){
    delete ps;
}

EX13

#include <iostream>
#include <vector>
#include <initializer_list>

struct X {
    X() { std::cout << "X()" << std::endl; }
    X(const X&) { std::cout << "X(const X&)" << std::endl; }
    X& operator=(const X&) { std::cout << "X& operator=(const X&)" << std::endl; return *this; }
    ~X() { std::cout << "~X()" << std::endl; }
};

void f(const X &rx, X x)//構
{
    std::vector<X> vec;
    vec.reserve(2);
    vec.push_back(rx);//構
    vec.push_back(x);//構
}

int main()
{
    X *px = new X;//構
    f(*px, *px);
    delete px;
    return 0;
}

順序:構構析構構析析析 –》 構構構構析析析析



13.1.4,三/五法則

需要析構函數則也需要拷貝和賦值函數。需要拷貝函數則需要構造函數,反之亦然。



13.1.6,阻止拷貝

??? iostream類阻止拷貝
???P451 第三段


EX18,19

Employee{
private:
    string name;
    int id;
    static int flag;
public:
    Employee(){id = ++flag;}
    Employee(string str):name(str){id = ++flag;}
    Employee(const Employee& e)= delete;
    Emplyee& operator=(const Employee& e)=delete;
}

int Employee::flag = 0;

在現實生活中拷貝或者賦值員工的個人信息沒有實際意義。


EX20,21 ???


13.2拷貝控制和資源管理


13.2.1,行爲像值的類

ex22

class HasPtr {
private:
    string *ps;
    int i;
public:
    HasPtr(const string& str){ps = new string(str);}
    HasPtr(const HasPtr& hp){
        ps = new string(*p.ps);
        i = hp.i;
    }
    HasPre& operator=(const HasPtr& hp){
        auto tem = new string(*p.ps);
        delete ps;//這是拷貝賦值運算,原來的地址空間需要回收
        ps = tem;
        i = hp.i;
        return *this;
    }
    ~HasPtr(){delete ps;}
}

ex25,26 ???



13.2.2行爲像指針的類

class HasPtr {
private:
    string *ps;
    int i;
    size_t *use;

public:
    HasPtr(const string& str):ps(new string(str)),i(0),use(new size_t(1)){}
    HasPtr(const HasPtr& hp):ps(hp.ps),i(hp.i),use(hp.use){++*use;}
    HasPre& operator=(const HasPtr& hp){
        ++*hp.use;//右側運算對象的空間引用計數器加1
        if(--(*use)==0){
            delete ps;
            delete use
        }//如果無指針指向左側運算對象,則釋放空間
        ps = hp.ps;
        i = hp.i;
        use = hp.use;
        return *this;
    }
    ~HasPtr(){
        if(--*use==0){
            delete ps;
            delete use;
        }
    }
}

13.28 ???


13.32

#include <string>
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class HasPtr
{
public:
    friend void swap(HasPtr&, HasPtr&);
    friend bool operator<(const HasPtr &lhs, const HasPtr &rhs);

    HasPtr(const std::string &s = std::string(),int num=0)
        : ps(new std::string(s)), i(num)
    { }

    HasPtr(const HasPtr &hp)
        : ps(new std::string(*hp.ps)), i(hp.i)
    { }

    HasPtr& operator=(HasPtr tmp)
    {
        this->swap(tmp);
        return *this;
    }
    void display() {
        cout << i << *ps << endl;
    }

    ~HasPtr()
    {
        delete ps;
    }

    void swap(HasPtr &rhs)
    {
        using std::swap;
        swap(ps, rhs.ps);
        swap(i, rhs.i);
        std::cout << "call swap(HasPtr &rhs)" << std::endl;
    }

    void show() const
    {
        std::cout << *ps << std::endl;
    }
private:
    std::string *ps;
    int i;
};

void swap(HasPtr& lhs, HasPtr& rhs)
{
    lhs.swap(rhs);
}

bool operator<(const HasPtr &lhs, const HasPtr &rhs)
{
    return *lhs.ps < *rhs.ps;
}

int main() {
    vector<HasPtr> vec_hp;
    HasPtr hp1("hi", 1);
    HasPtr hp2("ab", 2);
    HasPtr hp3("cd", 3);
    vec_hp.push_back(hp1);
    vec_hp.push_back(hp2);
    vec_hp.push_back(hp3);
    sort(vec_hp.begin(),vec_hp.end());
    for (auto i : vec_hp) {
        i.display();
    }

}


13.4,拷貝控制實例


發佈了57 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章