c++??復(fù)制消除問(wèn)題解決示例詳析
錯(cuò)誤示范
push_back 這么寫是錯(cuò)的:
template<class T> class threaded_message_queue { public: using lock = std::unique_lock<std::mutex>; void push_back(T t) { { lock l(_m); _data.push_back(std::move(t)); } _cv.notify_one(); } } };//
入?yún)?nbsp;T t
導(dǎo)致了調(diào)用者在這里會(huì)發(fā)生一次臨時(shí)對(duì)象 TMP 的復(fù)制,稍后在函數(shù)退出點(diǎn)處 TMP 還會(huì)被隱式析構(gòu)。所以這個(gè)寫法不是良構(gòu)。
至于函數(shù)體中的 std::move(t)
也就是聊勝于無(wú)了,它并不會(huì)讓 t
少掉 TMP 的復(fù)制,僅僅只是少掉了 t
到 _data
的一次復(fù)制而已。
正確工作
做模板類開(kāi)發(fā)時(shí),經(jīng)常會(huì)遇到 push_back 的這種場(chǎng)景。
正確的 push_back 應(yīng)該包含左值復(fù)制和右值移動(dòng)兩種語(yǔ)義,一般來(lái)說(shuō)像是這樣子:
template<class T> class threaded_message_queue { public: using lock = std::unique_lock<std::mutex>; void emplace_back(T &&t) { { lock l(_m); _data.template emplace_back(std::move(t)); } _cv.notify_one(); } void push_back(T const &t) { { lock l(_m); _data.push_back(t); } _cv.notify_one(); } } };
注意右值加上移動(dòng)語(yǔ)義才是一對(duì)搭配。T t
和移動(dòng)語(yǔ)義在一起只是一種錯(cuò)覺(jué)。
你還可以加上一個(gè) push_back 的移動(dòng)語(yǔ)義:
void push_back(T &&t) { { lock l(_m); _data.template emplace_back(std::move(t)); } _cv.notify_one(); }
這是因?yàn)榘凑占s定,emplace_back 通常采用模板變參并實(shí)現(xiàn) T 類的原位構(gòu)造。這個(gè)話題我在 C++ 中的原位構(gòu)造函數(shù)及完美轉(zhuǎn)發(fā) - 寫我們自己的 variant 包裝類 已經(jīng)有過(guò)一定的討論,這里就不詳述了。
X-class
hicc::debug::X
是一個(gè)專門用來(lái)調(diào)試 RVO,In-place construction,Copy Elision 等等特性的工具類,它平平無(wú)奇,只不過(guò)是在若干位置埋點(diǎn)冰打印 stdout 文字而已,這可以讓我們直觀觀察到哪些行為實(shí)際上發(fā)生了。
X-class 在構(gòu)造函數(shù)的入?yún)⒉糠钟邢嗨频臉?gòu)造:
namespace hicc::debug { class X { std::string _str; void _ct(const char *leading) { printf(" - %s: X[ptr=%p].str: %p, '%s'\n", leading, (void *) this, (void *) _str.c_str(), _str.c_str()); } public: X() { _ct("ctor()"); } ~X() { _ct("dtor"); } X(std::string &&s) : _str(std::move(s)) { _ct("ctor(s)"); } X(std::string const &s) : _str(s) { _ct("ctor(s(const&))"); } X &operator=(std::string &&s) { _str = std::move(s); _ct("operator=(&&s)"); return (*this); } X &operator=(std::string const &s) { _str = s; _ct("operator=(const&s)"); return (*this); } const char *c_str() const { return _str.c_str(); } operator const char *() const { return _str.c_str(); } }; } // namespace hicc::debug
以上就是c++ 復(fù)制消除問(wèn)題解決示例詳析的詳細(xì)內(nèi)容,更多關(guān)于c++ 復(fù)制消除問(wèn)題的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)通關(guān)時(shí)間復(fù)雜度和空間復(fù)雜度
對(duì)于一個(gè)算法,其時(shí)間復(fù)雜度和空間復(fù)雜度往往是相互影響的,當(dāng)追求一個(gè)較好的時(shí)間復(fù)雜度時(shí),可能會(huì)使空間復(fù)雜度的性能變差,即可能導(dǎo)致占用較多的存儲(chǔ)空間,這篇文章主要給大家介紹了關(guān)于C語(yǔ)言時(shí)間復(fù)雜度、空間復(fù)雜度的相關(guān)資料,需要的朋友可以參考下2022-04-04Qt qml實(shí)現(xiàn)動(dòng)態(tài)輪播圖效果
這篇文章主要為大家詳細(xì)介紹了Qt和qml實(shí)現(xiàn)動(dòng)態(tài)輪播圖效果的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下2024-12-12C++深入探究類與對(duì)象之友元與運(yùn)算符重載
友元就是讓一個(gè)函數(shù)或者類,訪問(wèn)另一個(gè)類中的私有成員;打個(gè)比方,這相當(dāng)于是說(shuō):朋友是值得信任的,所以可以對(duì)他們公開(kāi)一些自己的隱私,運(yùn)算符重載的實(shí)質(zhì)就是函數(shù)重載或函數(shù)多態(tài),運(yùn)算符重載是一種形式的C++多態(tài),目的在于讓人能夠用同名的函數(shù)來(lái)完成不同的基本操作2022-04-04OpenCV中C++函數(shù)imread讀取圖片的問(wèn)題及解決方法
利用C++函數(shù)imread讀取圖片的時(shí)候返回的結(jié)果總是空,而利用C函數(shù)cvLoadImage時(shí)卻能讀取到圖像。怎么回事?今天小編通過(guò)本教程給大家簡(jiǎn)單說(shuō)明原因2017-03-03VS2019配置BOOST的方法(v1.70.0庫(kù))
這篇文章主要介紹了VS2019配置BOOST的方法(v1.70.0庫(kù)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08