標籤:

【源碼眾讀】之問題解答,cpp_Part_3

前天組織了一場刷題,本來是想給大家熱鬧熱鬧,獎品都準備好了,結果一個參與的都沒有。

n

我還是回來繼續讀源碼了,沒完成的事總要一步一步做完才對。

n

struct Statics { n const std::shared_ptr<JsonValue> null = make_shared<JsonNull>(); n const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true); n const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false); n const string empty_string; n const vector<Json> empty_vector; n const map<string, Json> empty_map; n Statics() {} n}; nnstatic const Statics & statics() { n static const Statics s {}; n return s; n} nnstatic const Json & static_null() { n static const Json json_null; n return json_null; n}n

n

解讀1

n

這裡定義了一些靜態量,雖然語法比較容易看懂,但是具體的用途還看不出來,留著後面看。

n

Json::Json() noexcept : m_ptr(statics().null) {} nJson::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {} nJson::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {} nJson::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {} nJson::Json(bool value) : m_ptr(value ? statics().t : statics().f) {} nJson::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {} nJson::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {} nJson::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {} nJson::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {} nJson::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {} nJson::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {} nJson::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}n

n

解讀1

n

這一塊代碼負責定義Json類的構造函數。

n

可以看到在構造函數中只做了一件事,那就是為m_ptr賦值。

n

std::shared_ptr<JsonValue> m_ptr;

n

我們只看幾個特殊的賦值

n

解讀2

n

Json::Json() noexcept : m_ptr(statics().null) {}nJson::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}n

n

這兩處都是把statics()函數返回值的null成員賦值給m_ptr

n

回過頭去看一下,statics()返回的是Statics類型的常量引用,它的實現則是定義了一個局部靜態變數s,因此多次調用statics()方法時,返回的都是s的引用

n

static const Statics s {};nreturn s;n

n

PS: 這裡可以寫個demo試一下,在Statics的構造函數中加上日誌,看一下多次調用statics()方法時會輸出什麼。

n

代碼進一步用s.null初始化m_ptr

n

const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();n

n

這裡左邊用的是JsonValue, 右邊用的是JsonNull,關鍵就在於JsonVlaue是JsonNull的基類,如果兩個類沒用關係則肯定會報錯,那麼把兩者的左右位置對調呢?

n

解讀3

n

Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}n

n

用問號表達式的結果來初始化m_ptr

n

解讀4

n

後面的幾個構造函數的實現比較簡單,需要注意左值引用和右值引用的區別,以及move函數的用法

n

通常來說,我們無法將一個右值引用綁定到一個左值上,因為右值引用只能綁定到一個將要銷毀的對象,而左值是持久的

n

int &&rr1 = 42;n

n

rr1雖然是一個右值引用類型,但它是一個左值,因為它是一個變數,是持久的。

n

所以,下面的賦值是錯誤的

n

int &&rr2 = rr1;n

n

我們無法將一個右值引用綁定到一個右值引用類型的變數上。

n

move函數用來解決這個問題

n

int &&rr3 = std::move(rr1);n

n

move告訴編譯器,我們有一個左值,但是我們希望像右值一樣處理它。調用move之後,除了對rr1賦值或銷毀外,我們將不再使用它。

n

也正是這個原因,可以看到使用右值引用作為入參的幾個函數,都調用了move來進行值的傳遞

n

Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}n

n

move返回的是一個右值引用,所以調用JsonObject的下面這個構造函數

n

explicit JsonObject(Json::object &&value) : Value(move(value)) {}n

n

進一步調用了Value的構造函數

n

explicit Value(T &&value) : m_value(move(value)) {}n

n

在傳遞的過程中,move函數的返回值一直作為一個臨時量,而非變數。所以能夠作為下一級調用的實參。


推薦閱讀:

C++實現神經網路之四—神經網路的預測和輸入輸出的解析
《C++ Primer》讀書筆記-第十一章 03 關聯容器操作
當刷題遇見吐槽和涼席椅墊,完美!
15個C++項目列表
說說 C++ 的 Concept

TAG:C |