亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 4174 | 回復(fù): 5
打印 上一主題 下一主題

[C++] emplace_back似乎可以不用move就能實現(xiàn) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2015-11-25 23:05 |只看該作者 |倒序瀏覽
stl容器的emplace_back比push_back而言,用move語義來移動一個元素,而不是拷貝一個元素,所以效率可以更高。我看gcc的源碼,push_back(T&&)也是內(nèi)部用emplace_back一個move過的元素

問題:
但是這樣做是為了效率考慮的話,我感覺placement_new的效率更高啊,容器先reserve(),然后以reserve出來的空間作為地址,做new()來構(gòu)造一個新的元素,這樣一來連move都省掉了,豈不是更好。
感覺emplace_back需要依賴move語義,有點多次一舉的意思啊

論壇徽章:
2
青銅圣斗士
日期:2015-11-26 06:15:59數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-07-24 06:20:00
2 [報告]
發(fā)表于 2015-11-26 03:59 |只看該作者
回復(fù) 1# Ruckus優(yōu)科

  1. void push_back(const value_type& x);
  2. void push_back(value_type&& x);
  3. template <class... Args> void emplace_back(Args&&... args);
復(fù)制代碼
第1個是c++98的。
第2個是c++11的。 因為value_type&& x只能綁定右值, 所以可以將x用作move。
第3個也是c++11的。 Args&&不一定是右值引用, 這個東西叫universal references或forwarding references。
這個解釋起來有些復(fù)雜。。。 還是看 Universal References in C++11—Scott Meyers 比較專業(yè)。。。

于是可以先從另一個(也許會更容易)的方式看待C++11新加入的這兩貨 —— push_back(&&)和emplace_back —— 的不同, 就是emplace_back的參數(shù)個數(shù)。。。

push_back的右值重載,傳遞的始終是一個參數(shù), 類型是容器的元素類型。
vector<string> xs;
xs.push_back("implicit"); // 實際是調(diào)用/* non explict */ string(const char* s)構(gòu)造一個臨時的string對象
xs.push_back(string("explicit")); // 是顯式調(diào)用 string(const char* s)構(gòu)造。。。
xs.push_back(string("hello world", 5));  // 是調(diào)用 string (const char* s, size_t n) 構(gòu)造。。。
xs.push_back(string(6, '0')); // 調(diào)用 string (size_t n, char c) 。。。
xs.push_back(string());  // 調(diào)用 string() 默認構(gòu)造。。。
它們都是先用各種參數(shù)構(gòu)造一個臨時的string作為push_back的參數(shù), 通過它構(gòu)造出xs內(nèi)的那個元素, 即xs.back()。 然后銷毀那個臨時的string。
語義上總共兩個構(gòu)造。 一個析構(gòu)。 第2個構(gòu)造是通過move。

而emplace_back是不定長,不定類型的函數(shù)模板。
xs.emplace_back("explicit"); // string(const char* s)
xs.emplace_back("hello world", 5); // string (const char* s, size_t n)
xs.emplace_back(6, '0'); // string (size_t n, char c)
xs.emplace_back(); // string()
這些參數(shù)(包括最后一個沒有參數(shù))轉(zhuǎn)發(fā)到string的構(gòu)造函數(shù)(包括默認構(gòu)造函數(shù)), 直接構(gòu)造xs.back()。
語義上總共一個構(gòu)造。 零個析構(gòu)。

論壇徽章:
2
青銅圣斗士
日期:2015-11-26 06:15:59數(shù)據(jù)庫技術(shù)版塊每日發(fā)帖之星
日期:2016-07-24 06:20:00
3 [報告]
發(fā)表于 2015-11-26 05:14 |只看該作者
Ruckus優(yōu)科 發(fā)表于 2015-11-25 23:05
但是這樣做是為了效率考慮的話,我感覺placement_new的效率更高啊,容器先reserve(),然后以reserve出來的空間作為地址,做new()來構(gòu)造一個新的元素,這樣一來連move都省掉了,豈不是更好。
感覺emplace_back需要依賴move語義,有點多次一舉的意思啊


再看了一次問題,我好像誤解你的問題了。。。
emplace_back確實是直接placement new, 直接構(gòu)造, 無須move。 所以關(guān)鍵點還是在前面省略的Args&&。。。

它不是rvalue reference, 而是universal references。 是為了完美轉(zhuǎn)發(fā)(perfect forwarding), 保持參數(shù)的lvalue/rvalue性質(zhì)。
當是rvalue時, 就可以move, 而當是lvalue時, 就別move壞了。

假設(shè)X可以通過Y構(gòu)造:
struct Y {};
struct X {
      explicit X(Y const&);
      explicit X(Y&&);
};

vector<X> xs;
xs.emplace_back(Y()); // Y()產(chǎn)生臨時對象, 是右值, 調(diào)用X(Y&&)
Y y;
xs.emplace_back(y); // y是左值, 于是只能調(diào)用X(Y const&)
xs.emplace_back(move(y)); // move(y) cast到右值, 于是會調(diào)用X(Y&&)

可見emplace_back會維持參數(shù)的lvalue/rvalue的性質(zhì)并轉(zhuǎn)發(fā) —— 傳給emplace_back的是右值才調(diào)用X(Y&&), 否則就調(diào)用X(Y const&)。

除了使用universal references外, 實現(xiàn)perfect forwarding還有另一半工作要做。僅僅看聲明不夠。。。
以單參數(shù)為例:
template <typename T> void emplace_back1(T&& x)
{
      value_type* p = back_address(); // 這是新的末尾元素所在地址
      new(p) value_type(std::forward<T>(x)); // 以forward<T>(x)為參數(shù)placement new
}
forward是一個條件cast, 只有當確實以右值調(diào)用emplace_back1時, 它才會cast到右值引用, 否則它只會返回左值引用。
于是就可以調(diào)用合適的value_type。

emplace_back和emplace_back1類似, 都聲明為universal references, 并將參數(shù)使用std::forward進行帶條件的cast, 將lvalue或rvalue參數(shù)原樣轉(zhuǎn)發(fā)給X。
只是emplace_back是不定長參數(shù)。

具體解釋。。。  可以看Effective Modern C++。。。
Item 1: Understand template type deduction. 會說明:
1. void push_back(value_type&&)是rvalue reference, 而template <typename T> void emplace_back1(T&& x)是universal references
2. xs.emplace_back1(Y()), T會推演為Y, 而xs.emplace_back1(y), T會推演為Y&。

Item 28: Understand reference collapsing. 詳細介紹利用 reference collapsing 實現(xiàn) std::forward。


時隔多年。。。 Scott Meyers 叔叔繼續(xù)教C++信徒做人。。。

論壇徽章:
44
15-16賽季CBA聯(lián)賽之浙江
日期:2021-10-11 02:03:59程序設(shè)計版塊每日發(fā)帖之星
日期:2016-07-02 06:20:0015-16賽季CBA聯(lián)賽之新疆
日期:2016-04-25 10:55:452016科比退役紀念章
日期:2016-04-23 00:51:2315-16賽季CBA聯(lián)賽之山東
日期:2016-04-17 12:00:2815-16賽季CBA聯(lián)賽之福建
日期:2016-04-12 15:21:2915-16賽季CBA聯(lián)賽之遼寧
日期:2016-03-24 21:38:2715-16賽季CBA聯(lián)賽之福建
日期:2016-03-18 12:13:4015-16賽季CBA聯(lián)賽之佛山
日期:2016-02-05 00:55:2015-16賽季CBA聯(lián)賽之佛山
日期:2016-02-04 21:11:3615-16賽季CBA聯(lián)賽之天津
日期:2016-11-02 00:33:1215-16賽季CBA聯(lián)賽之浙江
日期:2017-01-13 01:31:49
4 [報告]
發(fā)表于 2015-11-26 12:17 |只看該作者
emplace_back本來就沒有copy也沒有move,它就是直接placement new的。
說move什么的是指參數(shù),比如你用一個臨時string對象作為參數(shù)去emplace_back一個string容器,那這個臨時string參數(shù)會move過去而不是copy過去,和用string&&構(gòu)造string是一樣的。

論壇徽章:
0
5 [報告]
發(fā)表于 2015-11-26 22:36 |只看該作者
OwnWaterloo 發(fā)表于 2015-11-26 05:14
再看了一次問題,我好像誤解你的問題了。。。
emplace_back確實是直接placement new, 直接構(gòu)造, 無須 ...


謝謝,不過我嘗試了一下emplace_back多個元素,似乎不行啊:

  1. #include <vector>
  2. #include <deque>
  3. #include <forward_list>
  4. using namespace std;

  5. int main()
  6. {
  7.     vector<int> vi;
  8.     vi.emplace_back(3,4);
  9.     cout << "Hello world!" << endl;
  10.     return 0;
  11. }
復(fù)制代碼
編譯報錯: ...gcc\4.8.1\include\c++\ext\new_allocator.h|120|error: new initializer expression list treated as compound expression [-fpermissive]

gcc抱的這個錯誤是什么含義?

論壇徽章:
1
2015年辭舊歲徽章
日期:2015-03-03 16:54:15
6 [報告]
發(fā)表于 2015-11-26 23:57 |只看該作者
本帖最后由 lost_templar 于 2015-11-26 23:57 編輯

回復(fù) 5# Ruckus優(yōu)科
  1. void emplace_back(Args&&... args);
復(fù)制代碼
里邊的 args... 是作為 vector<T> 中 T 的 constructor 的參數(shù)出現(xiàn)的,而 int 類型構(gòu)建的時候只能接受 0 個或 1 個參數(shù), 不是兩個。

可以這樣測試

  1. #include <vector>

  2. struct x
  3. {
  4.     template< typename ... Args >
  5.     x( Args&& ... ){}
  6. };



  7. void f()
  8. {
  9.     std::vector<x> vx;
  10.     vx.emplace_back( );
  11.     vx.emplace_back( vx );
  12.     vx.emplace_back( vx, vx );
  13.     vx.emplace_back( vx, vx, vx );
  14.     vx.emplace_back( vx, vx, vx, vx );
  15. }

復(fù)制代碼
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP