c++??復制消除問題解決示例詳析
錯誤示范
push_back 這么寫是錯的:
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 導致了調(diào)用者在這里會發(fā)生一次臨時對象 TMP 的復制,稍后在函數(shù)退出點處 TMP 還會被隱式析構。所以這個寫法不是良構。
至于函數(shù)體中的 std::move(t) 也就是聊勝于無了,它并不會讓 t 少掉 TMP 的復制,僅僅只是少掉了 t 到 _data 的一次復制而已。
正確工作
做模板類開發(fā)時,經(jīng)常會遇到 push_back 的這種場景。
正確的 push_back 應該包含左值復制和右值移動兩種語義,一般來說像是這樣子:
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();
}
}
};注意右值加上移動語義才是一對搭配。T t 和移動語義在一起只是一種錯覺。
你還可以加上一個 push_back 的移動語義:
void push_back(T &&t) {
{
lock l(_m);
_data.template emplace_back(std::move(t));
}
_cv.notify_one();
}這是因為按照約定,emplace_back 通常采用模板變參并實現(xiàn) T 類的原位構造。這個話題我在 C++ 中的原位構造函數(shù)及完美轉發(fā) - 寫我們自己的 variant 包裝類 已經(jīng)有過一定的討論,這里就不詳述了。
X-class
hicc::debug::X 是一個專門用來調(diào)試 RVO,In-place construction,Copy Elision 等等特性的工具類,它平平無奇,只不過是在若干位置埋點冰打印 stdout 文字而已,這可以讓我們直觀觀察到哪些行為實際上發(fā)生了。
X-class 在構造函數(shù)的入?yún)⒉糠钟邢嗨频臉嬙欤?/p>
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++ 復制消除問題解決示例詳析的詳細內(nèi)容,更多關于c++ 復制消除問題的資料請關注腳本之家其它相關文章!
相關文章
OpenCV中C++函數(shù)imread讀取圖片的問題及解決方法
利用C++函數(shù)imread讀取圖片的時候返回的結果總是空,而利用C函數(shù)cvLoadImage時卻能讀取到圖像。怎么回事?今天小編通過本教程給大家簡單說明原因2017-03-03

