{"cells":[{"cell_type":"markdown","metadata":{"id":"9xoK4OIjIfZA"},"source":["#計算機程式設計二\n","#第十三週上課內容\n","## Constructors\n","## 自訂 IntVec"]},{"cell_type":"code","execution_count":90,"metadata":{"colab":{"background_save":true,"base_uri":"https://localhost:8080/","height":132},"executionInfo":{"elapsed":411,"status":"error","timestamp":1670324115229,"user":{"displayName":"HT Chen","userId":"17748361917871513601"},"user_tz":-480},"id":"-q2PXK4m_NtS"},"outputs":[{"name":"stdout","output_type":"stream","text":["Writing test.cpp\n"]}],"source":["%%writefile test.cp\n","#include \u003ciostream\u003e\n","#include \u003calgorithm\u003e\n","#include \u003cinitializer_list\u003e\n","\n","class IntVec {\n"," public:\n","  IntVec(): size_{0}, capacity_{8}, elem_{new int [capacity_]} {\n","  }\n","\n","  IntVec(const IntVec\u0026 w): size_{w.size_}, capacity_{w.capacity_},\n","  elem_{new int [w.capacity_]} {\n","      for (size_t i=0; i\u003cw.size_; ++i)\n","        elem_[i] = w.elem_[i];\n","  }\n","\n","  IntVect(std::initializer_list\u003cint\u003e lst): size_{lst.size()},\n","  capacity_{8} {\n","      if (lst.size()*2 \u003e capacity_) {\n","          capacity_ = lst.size()*2;\n","      }\n","      elem_ = new int [capacity_];\n","      std::copy(lst.begin(), lst.end(), elem_);\n","  }\n","\n","  size_t size() {\n","      return size_;\n","  }\n","\n"," private:\n","  size_t size_;     // number of elements\n","  size_t capacity_; // upper bound of elements\n","  int *elem_;       // new elem_[???];\n","};\n","\n","int main()\n","{\n","    IntVec v;\n","    IntVec u{1, 2, 3, 4};\n","    IntVec w{v};\n","    std::cout \u003c\u003c v.size() \u003c\u003c std::endl;\n","    std::cout \u003c\u003c w.size() \u003c\u003c std::endl;\n","    std::cout \u003c\u003c u.size() \u003c\u003c std::endl;\n"," \n","}"]},{"cell_type":"markdown","metadata":{"id":"Kn8vOmK_hxui"},"source":["## 實作 Integer Vectors\n","### 介紹 initializer list, move constructor, move assignment\n","\n","\n","```c++\n","#include \u003ciostream\u003e\n","#include \u003cinitializer_list\u003e\n","#include \u003calgorithm\u003e\n","class IntVec {\n","};\n","```\n","\n","我們用一個常見的範例來當作練習:實作能夠動態增加元素的一維陣列 (vector)。為了方便解釋，我們只允許 vector 裡面放整數。我們把打算自訂的 class 取名為 IntVec，它需要三個 private members：\n","```c++\n","private:\n","    size_t size_;\n","    size_t capacity_;\n","    int* elem_;\n","```\n","\n","其中 `size_` 是用來記住 vector 中有實際上多少個元素， `capacity_` 則是目前 vector 可以容納的元素上限，另外 `elem_` 則是指標，用來指向實際存放整數的陣列的開頭位址。\n","\n","接下來就是定義所們需要的 public member functions。\n","\n","\n"]},{"cell_type":"markdown","metadata":{"id":"BQcmsMG4h6_g"},"source":["#### Constructors\n","首先是各種不同的 constructors。\n","\n","##### default constructor\n","我們要的 default constructor 應該會長得像底下這樣\n","```c++\n","    IntVec() : size{0}_, capacity_{8}, elem_{new int [capacity_]} {}\n","```\n","直接設定每個 member 的預設值，`size_` 是 0 表示 vector 裡面沒有任何元素， `capacity_` 是 8 則是預設最多能放 8 個整數，等到快放滿的時候，我們再動態調整大小。而 `elem_` 這個指標，預設會指向一個包含 8 個整數的連續空間，我們用 \n","`new int [需要的數量]` 來取得能夠放置指定數量的連續空間。\n","這個 constructor 的主體不需要做其他的事情，所以只有 `{ }`\n","當我們在主程式裡面寫\n","\n","```c++\n","\tIntVec v;\n","```\n","就會用上面的 default constructor 來產生物件。\n","\n","注意，在這個例子裡， class 裡面 member 宣告的順序不能調換成底下這樣，\n","\n","```c++\n","private:\n","    size_t size_;\n","    int* elem_;\n","    size_t capacity_;\n","```\n","\n","因為上面的初始設定中 `elem_` 會用到 `capacity_` 所以宣告順序必須先是\n","\n","```c++\n","    size_t capacity_;\n","    int* elem_;\n","```\n","\n","在 class 建構的時候，會依照 member 宣告的順序來產生他們的內容，而不是照他們在 initializer list 的順序，例如\n","\n","```c++\n","IntVec() : size{0}_, elem_{new int [capacity_]}, capacity_{8}  {}\n","```\n","\n","這裡即使調換順序也不會造成影響。\n","\n","\n","\n","### copy constructor\n","\n","```c++\n","    IntVec(const IntVec\u0026 w) : size_{w.size_}, capacity_{w.capacity_},\n","        elem_{new int [w.capacity_]}\n","    {\n","        std::cout \u003c\u003c \"copy constructor\\n\";\n","        for (size_t i=0; i\u003cw.size_; i++)\n","            elem_[i] = w.elem_[i];\n","    }\n","```\n","當我們再產生一個新的 vector 的時候，如果希望直接複製一個既有的 vector 的內容，就會用到 copy constructor。例如底下的用法\n","```c++\n","\tIntVec u{v};\n","```\n","或是\n","```c++\n","\tIntVec u = v;\n","```\n","所以 copy constructor 要做的事情，首先是設定對應的 members，包括 `size_` 和 `capacity_` 以及指標 `elem_`。我們一樣要先取得足夠的空間，然後用 `elem_` 記住該空間的啟始位址，再來就要把 `elem_` 的內容從傳入的 IntVect 複製過來。上面的 copy constructor 函數裡的 `for` 迴圈，就是為了把傳進來的參數 `w` 的 `elem_` 逐一複製到自己的 `elem_`。\n","\n"]},{"cell_type":"markdown","metadata":{"id":"g-a2YgQLiI_P"},"source":["\n","##### initializer list constructor\n","我們也希望能使用底下的寫法來產生新的 vector\n","```c++\n","\tIntVec v{1,2,3,4};\n","```\n","要達到這個效果，我們必須定義 constructor 能夠接收 initializer list 當作參數。\n","```c++\n","    IntVec(std::initializer_list\u003cint\u003e lst):\n","        size_{lst.size()}\n","    {\n","        capacity_ = (lst.size()*2\u003e8) ? lst.size()*2 : 8;\n","        elem_ = new int [capacity_];\n","        if (lst.size()\u003e0)\n","            std::copy(lst.begin(), lst.end(), elem_);\n","    }\n","```\n","這要用到 ``` std::initializer_list\u003cT\u003e``` 來達成，所以我們在程式碼的最前面加了\n","`#include \u003cinitializer_list\u003e`。\n","傳入的參數 lst 是一個由整數構成的 initializer list，當我們在程式碼裡面寫類似 `{1,2,3,4}` 這樣的東西，就會被解讀為 initializer list 然後做對應的處理。我們可以用 `.size()` 函數來取得 initializer list 的大小，然後用 `.begin()` 和 `.end()` 來取得第一個元素和最後一個元素的位址，如此一來就可以用 `std::copy` 函數，來將 initializer list 的內容複製到我們自訂的 vector 的 `elem_` 指標所指到的那塊空間中。\n","\n","\n","##### 直接指定要產生的 vector 的大小\n","```c++\n","    IntVec(size_t sz):\n","        size_{sz},\n","        capacity_{2*sz},\n","        elem_{new int [2*sz]} { std::cout \u003c\u003c \"growing...\\n\"; }\n","\n","```\n","我們先取得兩倍大的空間，預備讓後續新增的元素可以直接放入，不需要每次都調整 `elem_` 的大小。\n","有一個小地方要注意，當我們在程式碼裡面寫\n","```c++\n","\tIntVec t{30};\n","```\n","會使用 initializer list 對應的 constructor，產生一個 vector 裡面只放了一個元素 `30`。如果是\n","```c++\n","\tIntVec t(30);\n","```\n","才會是產生一個能夠放至少 30 個整數的 vector。\n","\n","#### Desctructor\n","物件消失時要把 elem_ 占用的空間還回去。\n","```c++\n","    ~IntVec() {\n","        delete [] elem_;\n","    }\n","```\n","\n","#### Operators\n","我們還要自訂 operators。例如為了讓 `IntVec` 也能像一般的 array 使用方括號`[]`來取得元素的內容，我們在 class 裡面加入\n","```c++\n","    int \u0026 operator[](int i) {\n","    \t// no boundary check\n","        return elem_[i];\n","    }\n","```\n","這樣一來，如果程式碼裡面寫\n","```c++\n","\tIntVec v{5,10,15,20};\n","    std::cout \u003c\u003c v[2] \u003c\u003c std::endl;\n","    v[2] = 16;\n","    std::cout \u003c\u003c v[2] \u003c\u003c std::endl;\n","```\n","就可以在螢幕上顯示出 v 的編號`2` 的元素 `15`，或是把值改成 `16`。\n","\n","##### copy assignment\n","```c++\n","  IntVec\u0026 operator=(const IntVec\u0026 w)\n","    {\n","        IntVec v{w};\n","        std::cout \u003c\u003c \"copy assignment\\n\";\n","        std::swap(elem_, v.elem_);\n","        size_ = v.size_;\n","        capacity_ = v.capacity_;\n","        return *this;\n","    }\n","```\n","我們也重新定義 `=`，這樣才能夠在程式碼裡面寫\n","```c++\n","\tIntVec s{1,2,3,4};\n","  IntVec t{5,6,7};\n","  t = s;\n","```\n","上面的程式用到了一些慣用的寫法。首先在函數中產生一個 local object `v`，`IntVec v{w};`，它的內容直接從 `w` 複製過來，當這個函數結束的時候，`v`會被清除掉 (因為有 destructor)。接下來我們把 `elem_` 和 `v.elem_` 兩個指標交換，如此一來，自已 (this) 就會取得和 `w` 完全相同的 `elem_` 內容，但 `v` 的 `elem_` 則會變成是 this 原本的 `elem_` 內容，最後當 `v` 被清除的時候，就會一併清除原本 this 所擁有的 `elem_`。\n","\n","##### 重新定義 operator\u003c\u003c\n","這個 operator 不是 IntVec 的 member function，只是為了顯示\n","```c++\n","std::ostream\u0026 operator\u003c\u003c(std::ostream\u0026 os, IntVec\u0026 v)\n","{\n","    os \u003c\u003c \"[\";\n","    for (size_t i=0; i\u003cv.size_; i++)\n","        os \u003c\u003c v[i] \u003c\u003c \", \";\n","    os \u003c\u003c \"]\";\n","    return os;\n","}\n","```\n","所以我們在 class 裡面列為 friend，這樣才能使用 `.size_`。\n","```c++\n","\tfriend std::ostream\u0026 operator\u003c\u003c(std::ostream\u0026 os, IntVec\u0026 v);\n","```\n","\n","##### 模仿實作 push_back 函數\n","我們希望也能用 `push_back` 在 vector 的最後加入新的資料。\n","```c++\n","    void push_back(const int val) {\n","        if (size_+1 \u003e= capacity_) {\n","            IntVec tmp(capacity_);\n","            capacity_ = tmp.capacity_;\n","            for (size_t i=0; i\u003csize_; i++)\n","                tmp.elem_[i] = elem_[i];\n","            std::swap(elem_, tmp.elem_);\n","        }\n","        elem_[size_] = val;\n","        ++size_;\n","    }\n","```\n","正常情況只需要直接在 `elem_[size_]` 放入新的資料，並且`++size_;`。\n","如果 `capacity_` 不夠放新的資料，就要先產生一個新的足夠的空間 (用 local object 方式)，把舊的資料複製過去，然後 swap，這樣當 local object 被清除時，就會一併清掉舊的資料。\n"]},{"cell_type":"markdown","metadata":{"id":"PQKSG0mRiQEo"},"source":["\n","#### 與 rvalue reference 有關的兩個 member functions\n","\n","##### move constructor\n","\n","```c++\n","    IntVec(IntVec\u0026\u0026 w): size_{w.size_}, capacity_{w.capacity_}, elem_{w.elem_}\n","    {\n","        std::cout \u003c\u003c \"move constructor\\n\";\n","        w.size_ = 0;\n","        w.capacity_ = 0;\n","        w.elem_ = nullptr;\n","    }\n","```\n","\n","##### move assignment\n","```c++\n","    IntVec\u0026 operator=(IntVec\u0026\u0026 w) {\n","        std::cout \u003c\u003c \"move assignment\\n\";\n","        if (this != \u0026w) {\n","            delete [] elem_;\n","\n","            elem_ = w.elem_;\n","            size_ = w.size_;\n","            capacity_ = w.capacity_;\n","\n","            w.elem_ = nullptr;\n","            w.size_ = 0;\n","            w.capacity_ = 0;\n","        }\n","        return *this;\n","    }\n","```\n","\n","以 move assignment 為例，參數的 type 是 `IntVec\u0026\u0026`，兩個 ref 符號，表示它接收的是 rvalue reference，和 copy assignment 的參數 `IntVec\u0026` 不同 (只有一個 ref 符號，是 lvalue reference)。所謂的 lvalue，是指可以放在等號左邊的東西，例如 `int a = 3;` 其中的整數變數 a 就是可以放在等號左邊的東西，而相對地，3 是不能放在等號左邊的東西 (我們不會寫 `3 = 5;` 或 `3 = x;`)，我們稱作 rvalue。引用 Bjarne Stroustrup \"The C++ Programming Language (4th Edition)\" 書中的話\n","\n","\u003e\u003e an rvalue reference is a reference to something that nobody else can assign to, so that we can safely “steal” its value.\n","\n","因為我們有實際寫出 move assignment 版本的 `operator=`，所以如果程式碼有用到\n","```c++\n","\tIntVec w, v;\n","  w = {2,3,4};\n","```\n","等號右邊的 `{2,3,4}` 是 rvalue，所以可以對應到 rvalue reference，因此 move assignment 版本的 `operator=` 會被呼叫。這時候發生的事情是，先用 initializer list 產生一個暫時的物件，然後 move assignment 會把那個暫時的物件的內容搬到 `w`，假設我們沒有實作 move assignment，則上面的式子只好用 copy assignment 來達成，這時候發生的事情則會是，先用 initializer list 產生一個暫時的物件，然後用 copy assignment 來複製，過程中還會用 copy constructor 先產生一個臨時的副本，讓 w 可以得到我們想複製的內容。所以，這種情況下，有實際做出 move assignment 可以省掉產生臨時副本。\n","\n","我們可以把上面的 move constructor 和 move assignment 範例當成慣用寫法學起來，套用到其他自訂的 class。"]},{"cell_type":"markdown","metadata":{"id":"3Mn1B7BSiecr"},"source":["## 完整的程式碼\n"]},{"cell_type":"code","execution_count":10,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":441,"status":"ok","timestamp":1670314652155,"user":{"displayName":"HT Chen","userId":"17748361917871513601"},"user_tz":-480},"id":"xpVN59OgiWbs","outputId":"87414a50-5cad-424d-f50c-509f4812df12"},"outputs":[{"name":"stdout","output_type":"stream","text":["Overwriting E13_01.cpp\n"]}],"source":["%%writefile E13_01.cpp\n","#include \u003ciostream\u003e\n","#include \u003cinitializer_list\u003e\n","#include \u003calgorithm\u003e\n","class IntVec {\n","public:\n","    IntVec() :\n","        size_{0},\n","        capacity_{8},\n","        elem_{new int [capacity_]} { std::cout\u003c\u003c\"Default constructor\\n\";}\n","\n","    IntVec(const IntVec\u0026 w) : size_{w.size_}, capacity_{w.capacity_},\n","        elem_{new int [w.capacity_]}\n","    {\n","        std::cout \u003c\u003c \"copy constructor\\n\";\n","        for (size_t i=0; i\u003cw.size_; i++)\n","            elem_[i] = w.elem_[i];\n","    }\n","\n","    IntVec(std::initializer_list\u003cint\u003e lst):\n","        size_{lst.size()}\n","    {\n","        capacity_ = (lst.size()*2\u003e8) ? lst.size()*2 : 8;\n","        elem_ = new int [capacity_];\n","        if (lst.size()\u003e0)\n","            std::copy(lst.begin(), lst.end(), elem_);\n","    }\n","\n","    IntVec(size_t sz):\n","        size_{sz},\n","        capacity_{2*sz},\n","        elem_{new int [2*sz]} { std::cout \u003c\u003c \"growing...\\n\"; }\n","\n","\n","    ~IntVec() {\n","        delete [] elem_;\n","    }\n","\n","    int \u0026 operator[](int i) {\n","        // no boundary check\n","        return elem_[i];\n","    }\n","\n","\n","    IntVec\u0026 operator=(const IntVec\u0026 w)\n","    {\n","        IntVec v{w};\n","        std::cout \u003c\u003c \"copy assignment\\n\";\n","        std::swap(elem_, v.elem_);\n","        size_ = v.size_;\n","        capacity_ = v.capacity_;\n","        return *this;\n","    }\n","\n","    // rvalue reference\n","    IntVec(IntVec\u0026\u0026 w): size_{w.size_}, capacity_{w.capacity_}, elem_{w.elem_}\n","    {\n","        std::cout \u003c\u003c \"move constructor\\n\";\n","        w.size_ = 0;\n","        w.capacity_ = 0;\n","        w.elem_ = nullptr;\n","    }\n","\n","    // rvalue reference\n","    IntVec\u0026 operator=(IntVec\u0026\u0026 w) {\n","        std::cout \u003c\u003c \"move assignment\\n\";\n","        if (this != \u0026w) {\n","            delete [] elem_;\n","\n","            elem_ = w.elem_;\n","            size_ = w.size_;\n","            capacity_ = w.capacity_;\n","\n","            w.elem_ = nullptr;\n","            w.size_ = 0;\n","            w.capacity_ = 0;\n","        }\n","        return *this;\n","    }\n","\n","\n","    void push_back(const int val) {\n","        if (size_+1 \u003e= capacity_) {\n","            IntVec tmp(capacity_);\n","            capacity_ = tmp.capacity_;\n","            for (size_t i=0; i\u003csize_; i++)\n","                tmp.elem_[i] = elem_[i];\n","            std::swap(elem_, tmp.elem_);\n","        }\n","        elem_[size_] = val;\n","        ++size_;\n","    }\n","\n","    friend std::ostream\u0026 operator\u003c\u003c(std::ostream\u0026 os, IntVec\u0026 v);\n","\n","private:\n","    size_t size_;\n","    size_t capacity_;\n","    int* elem_;\n","};\n","\n","std::ostream\u0026 operator\u003c\u003c(std::ostream\u0026 os, IntVec\u0026 v)\n","{\n","    os \u003c\u003c \"[\";\n","    for (size_t i=0; i\u003cv.size_; i++)\n","        os \u003c\u003c v[i] \u003c\u003c \", \";\n","    os \u003c\u003c \"]\";\n","    return os;\n","}\n","\n","int main()\n","{\n","    IntVec t;\n","    IntVec v{1,2,3};\n","    std::cout \u003c\u003c v \u003c\u003c std::endl;\n","    for (int e; std::cin\u003e\u003ee;)\n","        v.push_back(e);\n","    std::cout \u003c\u003c v \u003c\u003c std::endl;\n","    IntVec w{v};\n","    std::cout \u003c\u003c w \u003c\u003c std::endl;\n","    w = {3,4,5};\n","    std::cout \u003c\u003c w \u003c\u003c std::endl;\n","    IntVec u = std::move(w);\n","    u[2] = 6;\n","    std::cout \u003c\u003c u \u003c\u003c std::endl;\n","    std::cout \u003c\u003c w \u003c\u003c std::endl;\n","}"]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":15516,"status":"ok","timestamp":1670314672794,"user":{"displayName":"HT Chen","userId":"17748361917871513601"},"user_tz":-480},"id":"2_x0H8QvtCNZ","outputId":"2a9cc132-149a-489f-9ccc-8ab813ab60b3"},"outputs":[{"name":"stdout","output_type":"stream","text":["Default constructor\n","[1, 2, 3, ]\n","1 2 3 4 5 8 7 9\n","growing...\n","∂\n","[1, 2, 3, 1, 2, 3, 4, 5, 8, 7, 9, ]\n","copy constructor\n","[1, 2, 3, 1, 2, 3, 4, 5, 8, 7, 9, ]\n","move assignment\n","[3, 4, 5, ]\n","move constructor\n","[3, 4, 6, ]\n","[]\n"]},{"data":{"text/plain":[]},"execution_count":11,"metadata":{},"output_type":"execute_result"}],"source":["%%shell\n","g++ E13_01.cpp -o E13_01 -std=c++1z\n","./E13_01"]},{"cell_type":"code","execution_count":87,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":1040,"status":"ok","timestamp":1670321057874,"user":{"displayName":"HT Chen","userId":"17748361917871513601"},"user_tz":-480},"id":"drujLDHMvaiw","outputId":"17b306cd-6602-403a-abfa-c0e6ab31a596"},"outputs":[{"name":"stdout","output_type":"stream","text":["Overwriting E13_02.cpp\n"]}],"source":["%%writefile E13_02.cpp\n","#include \u003ciostream\u003e\n","#include \u003cinitializer_list\u003e\n","#include \u003calgorithm\u003e\n","\n","template\u003ctypename T\u003e\n","struct Item {\n","  size_t idx;\n","  T elem;\n","};\n","\n","\n","template\u003ctypename T\u003e\n","class DoubleVecSparse {\n","public:\n","    DoubleVecSparse() :\n","        size_{0},\n","        capacity_{8},\n","        item_{new Item\u003cT\u003e [capacity_]} { std::cout\u003c\u003c\"Default constructor\\n\";}\n","\n","    DoubleVecSparse(const DoubleVecSparse\u0026 w) : size_{w.size_}, capacity_{w.capacity_},\n","        item_{new Item\u003cT\u003e [w.capacity_]}\n","    {\n","        std::cout \u003c\u003c \"copy constructor\\n\";\n","        for (size_t i=0; i\u003cw.size_; i++)\n","            item_[i] = w.item_[i];\n","    }\n","\n","\n","    DoubleVecSparse(std::initializer_list\u003cItem\u003cT\u003e\u003e lst):\n","        size_{lst.size()}\n","    {\n","        capacity_ = (lst.size()*2\u003e8) ? lst.size()*2 : 8;\n","        item_ = new Item\u003cT\u003e [capacity_];\n","        if (lst.size()\u003e0)\n","            std::copy(lst.begin(), lst.end(), item_);\n","        organize();\n","    }\n","\n","    DoubleVecSparse(size_t sz):\n","        size_{sz},\n","        capacity_{2*sz},\n","        item_{new Item\u003cT\u003e [2*sz]} { std::cout \u003c\u003c \"growing...\\n\"; }\n","\n","\n","    ~DoubleVecSparse() {\n","        delete [] item_;\n","    }\n","\n","    T\u0026 operator[](size_t idx) {\n","        // no boundary check\n","        for (size_t i=0; i\u003csize_; ++i) {\n","          if (item_[i].idx == idx) \n","            return item_[i].elem;\n","        }\n","\n","        if (size_+1 \u003e= capacity_) {\n","            DoubleVecSparse\u003cT\u003e tmp(capacity_);\n","            capacity_ = tmp.capacity_;\n","            for (size_t i=0; i\u003csize_; i++)\n","                tmp.item_[i] = item_[i];\n","            std::swap(item_, tmp.item_);\n","        }\n","        size_t prev = size_++;\n","        item_[prev] = Item\u003cT\u003e{idx, T{}};\n","        organize();\n","        for (size_t i=0; i\u003csize_; ++i) {\n","          if (item_[i].idx == idx) \n","            return item_[i].elem;\n","        }\n","    }\n","\n","    DoubleVecSparse\u0026 operator=(const DoubleVecSparse\u0026 w)\n","    {\n","        DoubleVecSparse v{w};\n","        std::cout \u003c\u003c \"copy assignment\\n\";\n","        std::swap(item_, v.item_);\n","        size_ = v.size_;\n","        capacity_ = v.capacity_;\n","        return *this;\n","    }\n","\n","    // rvalue reference\n","    DoubleVecSparse(DoubleVecSparse\u0026\u0026 w): size_{w.size_}, capacity_{w.capacity_}, item_{w.item_}\n","    {\n","        std::cout \u003c\u003c \"move constructor\\n\";\n","        w.size_ = 0;\n","        w.capacity_ = 0;\n","        w.item_ = nullptr;\n","    }\n","\n","    // rvalue reference\n","    DoubleVecSparse\u0026 operator=(DoubleVecSparse\u0026\u0026 w) {\n","        std::cout \u003c\u003c \"move assignment\\n\";\n","        if (this != \u0026w) {\n","            delete [] item_;\n","\n","            item_ = w.item_;\n","            size_ = w.size_;\n","            capacity_ = w.capacity_;\n","\n","            w.item_ = nullptr;\n","            w.size_ = 0;\n","            w.capacity_ = 0;\n","        }\n","        return *this;\n","    }\n","\n","    template\u003ctypename S\u003e\n","    friend std::ostream\u0026 operator\u003c\u003c(std::ostream\u0026 os, DoubleVecSparse\u003cS\u003e\u0026 v);\n","\n","    void organize() {\n","      std::sort(item_, item_+size_, \n","        [](Item\u003cT\u003e const \u0026a, Item\u003cT\u003e const \u0026b) {\n","            return a.idx \u003c b.idx; \n","        });\n","    }\n","private:\n","    size_t size_;\n","    size_t capacity_;\n","    Item\u003cT\u003e* item_;\n","};\n","\n","template\u003ctypename S\u003e\n","std::ostream\u0026 operator\u003c\u003c(std::ostream\u0026 os, DoubleVecSparse\u003cS\u003e\u0026 v)\n","{\n","    os \u003c\u003c \"[\";\n","    for (size_t i=0; i\u003cv.size_; i++)\n","        os \u003c\u003c \"(\" \u003c\u003c v.item_[i].idx \u003c\u003c \", \" \u003c\u003c v.item_[i].elem \u003c\u003c \"), \";\n","    os \u003c\u003c \"]\";\n","    return os;\n","}\n","\n","int main()\n","{\n","    DoubleVecSparse\u003cdouble\u003e v{{301, 2.5}, {200, 3.8}, {300, 0.7}};\n","    std::cout \u003c\u003c v \u003c\u003c std::endl;\n","\n","    std::cout \u003c\u003c v[201] \u003c\u003c std::endl;\n","    v[201] = 3.14;\n","    std::cout \u003c\u003c v \u003c\u003c std::endl;\n","}"]},{"cell_type":"code","execution_count":88,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":1733,"status":"ok","timestamp":1670321062829,"user":{"displayName":"HT Chen","userId":"17748361917871513601"},"user_tz":-480},"id":"zBautBu2j3bs","outputId":"bca909d9-3653-4c2a-f945-bb74902960c3"},"outputs":[{"name":"stdout","output_type":"stream","text":["[(200, 3.8), (300, 0.7), (301, 2.5), ]\n","0\n","[(200, 3.8), (201, 3.14), (300, 0.7), (301, 2.5), ]\n"]},{"data":{"text/plain":[]},"execution_count":88,"metadata":{},"output_type":"execute_result"}],"source":["%%shell\n","g++ E13_02.cpp -o E13_02 -std=c++1z\n","./E13_02"]}],"metadata":{"colab":{"authorship_tag":"ABX9TyNODw1MrQmCZWj+nxHv7R2U","name":"","provenance":[{"file_id":"1AB3RNlLfkZBSZKu6_Wh20CkIpbxfJIve","timestamp":1663461789208}],"version":""},"gpuClass":"premium","kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0}