1. 程式人生 > >C++程式設計語言1-3部分:筆記

C++程式設計語言1-3部分:筆記

虛擬函式:常見的做法是編譯器將虛擬函式的名字轉換成函式指標表中對應的索引值,這張表就是所謂的虛擬函式表(vtbl)每個含有虛擬函式的類都有自己的vtbl用於辨識虛擬函式;

return unique_ptr<Shape>  {new Circle{p,r}}
基於上述定義,編譯器將選擇移動建構函式(move constructor)來執行從函式中移出返回值的任務,這意味著r=x+y+z不需要再拷貝Vector,只是移動它就足夠了.

Vector::Vector(Vector&& a)
:elem{a.elem},sz{a.sz}{
    a.elem = nullptr;
    a.sz = 0;
}

Vector::Vector(Vector&& a)
:elem{a.elem},sz{a.sz}{
    a.elem = nullptr;
    a.sz = 0;
}

Shape(Shape&&) = delete;
Shape& operator = (Sape&&) = delete;//抑制操作


移動建構函式不接受const實參,畢竟移動建構函式最終要刪除掉它的實參中的值,移動賦值運算子(move assignment)的定義與之類似;
當右值引用被用作初始化器或者賦值操作的右側運算物件時,程式將使用移動操作;
Vector x(10);
Vector y(10);
Vector z(10);
z = x;
y = std::move(x) ; //執行移動操作,C++標準庫的move()負責返回實參的右值引用;
return z; //移動操作

z = x;//拷貝操作;

Vector x = v1; //這個是初始化,不是過載的=,
x = v1; //初始化後,用這個賦值,才是初始化;
過載的方法則是:先申請空間,拷貝舊元素.刪除新元素,返回*this;
x = v1 //x.operator=(T v1) ; //得這樣理解才能知道為何返回*this;

Vector::Vector(Vector&& a)
:elem{a.elem},
sz{a.sz}{
  a.elem = nullptr;
  a.sz = 0;
}


封裝是編譯期的概念,是針對型別而非物件的,在類的成員函式中可以訪問同類型例項物件的私有成員變數.

**類的成員函式中可以訪問同類型例項物件的私有成員變數.
當右值引用被用作初始化器或者賦值操作的右側運算物件時,程式將使用移動操作.
移動後,源物件所進入的狀態應該能允許執行解構函式,我們也應該允許為一個移動操作後的源物件賦值;

移動的用法:
std::vector<thread> my_threads;

thread t{heartbeat};
my_threads.push_back(move(t));

Sharp(const Sharp7) = delete; //沒有拷貝建構函式;

Vector<list<int>> vli(40);

模板的一個特殊用途是函式物件,我們可以像呼叫函式一樣使用函式物件.
//小於5?

template<typename T>
class Less_than{
    const T val;
public:
    Less-than(const T& v):val(v){}
    bool operator()(const T& x) const {return x < val;} //謂詞
};
用法:
Less_than<int> lit{42}; //初始化一個類,類的值為42,然後過載()
這樣呼叫lit(43);;就會用42與43比;返回布林值;
由於是模板,則string;
Less_than<string> its{"backet"};
bool b1 = lti(n);

作為演算法:template<typename C, typename P>
int count(const C& c, P pred){
    int cnt = 0;
    for(const auto& x:c)
        if(pred(x))
            ++cnt;
        return cnt;
}
}

一個謂詞的返回值要麼是true,或false;
使用:void f(const Vector<int>& vec,const list<string>& lst, int x, const string& s)
{
    cout << "number of values less than"<<x
        << count(vec,Less_than<int> {x}) << '\n';
}

[&](int a){return a < x;}
[&]是一個捕獲列表,它指明所用的區域性名字,如(X)將通過引用訪問,如果我們希望只"捕獲X",則[&x],取值[=x],[]什麼都不捕獲,則為空;

可變引數模板:
別名:

using El = typename C:value_type;
using int32 = int;

using 可以和template結合使用:

template<typename Value>
using String_map = Map<string,Value>;

string_map<int> m;   //m則為Map<string,int>

std::string s {"for"};
std::list<std::string> slong {"gooo","listx"};


-----------------------------------------------
struct Entry {
    string name;
    int number;
    //friend ostream& operator<<(ostream&, Entry&);
};

ostream& operator<<(ostream &os, Entry &pd) {
    os << pd.name << " " << pd.number ;
    return os;
}

map通常用平衡二叉樹實現;

map<string,int> phone_book{"David Hum",12345};

map 有序性;空間佔用,適合有序的
unordered_map 無序,適合查詢;unordered_map的用法和map是一樣的,提供了 insert,size,count等操作,並且裡面的元素也是以pair型別來存貯的。

forward_list<T>單向連結串列
deque<T> 雙端佇列
multiset<T>可重集合
multimap<K,V>允許重複關鍵字的map
unordered_multimap<K,V>
unordered_set<T>
unorder_multiset<T>

容器介面卡:queue<T>,statck<T>,deque<T>,priority_queue<T>.
定長資料array<T,N>,bitset<N>

要排序,則要過載operator<;
void f (vector<Entry>& vec, list<Entry>& lst)
{
    sort(vec.begin(),vec.end());
    unique_copy(vec.begin(),vec.end(),lst.begin());
}

template<typename C, typename V>
vector<typename C::iterator> find_all(C& c,Vv){
    typename必不可以,通知編譯器C的iterator為某種型別,而非值;
}

return unique_ptr<x>{new X{i}} //建立一個X,然後立即把它賦給nuique_ptr.
--------------------------------
shared_ptr在很多方面都和unique_ptr相似,shared_ptr的物件使用拷貝操作而非移動操作.

標準庫直接支援在單一地址空間內併發執行多個執行緒,C++提供了一個適合的記憶體模型和一套原子操作.
併發設施: thread,mutex,lock,packaged_task,future;

void f() //函式

struct F{
    void operator()();
};

F//函式物件; F呼叫運算子;

thread t1{f};//在獨立的執行緒中執行
thread t2{F()};

t1.join();
t1.join();

join()保證我們線上程完成後才退出user().join()的意思是,等待執行緒結束.

---------------
互斥:
mutex m;
thread使用lock()操作來獲取一個互斥物件;
unique_lock<mutex> lock{m};

using namespace std::chrono;
---------------------------------------------    
auto t0 = high_resolution_clock::now();
this_thread::sleep_for(milliseconds{ 1000 });
auto t1 = high_resolution_clock::now();
std::cout << "----------------------------" << std::endl;
std::cout << duration_cast<nanoseconds>(t1 - t0).count();
  //std::cout <<typeid(t0).name();
std::getchar();
----------------------------------------------
queue<Message> mquess;
condition_variable 由mutex標頭檔案提供;通訊用的條件變數
mutex mmutex;

std::unique_lock物件以獨佔所有權的方式(unique owership)管理mutex物件的上鎖和解鎖操作,即在unique_lock物件的宣告週期內,它所管理的鎖物件會一直保持上鎖狀態;而unique_lock的生命週期結束之後,它所管理的鎖物件會被解鎖。unique_lock具有lock_guard的所有功能,而且更為靈活。雖然二者的物件都不能複製,但是unique_lock可以移動(movable),因此用unique_lock管理互斥物件,可以作為函式的返回值,也可以放到STL的容器中。

consumer()消費者:
while(true){
unique_lock<mutex> lck{mmutex};
while(mcond.wait(lck))//釋放lck並等待
    auto m=mqueue.front();//
    mqueue.pop();
    lck.unlock();
       //..處理m...
    }
}

void producer(){
{
    while(true){
    Message m;
    unique_lock<mutex> lck{mmm}//保護佇列上的操作
    mqueue.push(m);
    mcond.notify_one(); //通知,釋放鎖(在作用域結束)
}
標準庫的高層次抽象:

<future>標頭檔案:
future和promise用來從一個獨立執行緒上創建出的任務返回結果;
package_task是幫助啟動任務以及連線返回結果的機制;
async()以類似呼叫函式的方式啟動一個任務;
future和promise的關鍵點是它們允許在兩個任務間傳輸值,而無須顯式使用鎖.系統高效地實現了這種傳輸.當一個任務需要向另一個任務傳輸某個值時,它把值放入promise中;