N3495 inplace realloc

617 views

Published on

A presentation about inplace realloc at C++14 Study meeting in Japan.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
617
On SlideShare
0
From Embeds
0
Number of Embeds
23
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

N3495 inplace realloc

  1. 1. N3495 inplace realloc 2013/12/14 13:30 to 18:00 に開催された、C++14勉強会 http://atnd.org/events/45289 での発表内容に、その後のフォローアップ内容を追記 SC22WG21 エキスパート 近藤 貴俊 (株式会社 オージス総研) 2014/1/30 1
  2. 2. N3495 提案概要 • 提案者 – Ariane van der Steldt ariane@stack.nl • 提案日 – 2012-12-07 • std::allocator_traits にC言語のreallocのよう に アロケート済みメモリのリサイズが可能 な インターフェースを追加しようという提 案 2014/1/30 2
  3. 3. N3495 IV 提案インターフェース 2014/1/30 template<typename Alloc> class std::allocator_traits { public: リサイズしたいメモリのポインタ ... /* Existing definition. */ static pointer alloc_resize(Alloc& a, pointer p, size_type n_cur, size_type n_new) { 現在の(変更前の)サイズ 変更後のサイズ /* * p, having n_cur elements, reallocのようにメモリの移動は行わない * would change to having n_new elements. * If the allocator does not support this, * std::bad_alloc() is thrown. 要素を増やすことができない場合は、 std::bad_alloc()をthrow * * (p, n_cur) must refer to a previous allocation, * or the behaviour is undefined. 前回の確保に対応していないのを渡したら * undefined behavior * This function is implemented as: * a.alloc_resize(p, n_cur, n_new) iff implemented by Alloc, * or as * throw std::bad_alloc() otherwise. */ return p; 実装されていない場合はstd::bad_alloc()をthrow } }; 3
  4. 4. IV N3495 標準ライブラリの変更 • 全ての連続したストレージを持つコンテ ナにおいて、allocateしてからmoveする箇 所があればその前に、alloc_resizeの処理を 追加する。 2014/1/30 4
  5. 5. V N3495 失敗時にbad_allocを返すことについて • mis-useの可能性を最小化する – 例外なので戻り値チェック漏れがない • アロケータの実装とメモリの使用状況に よるが、極めて頻繁に例外発生パスを通 過し得る 2014/1/30 5
  6. 6. V N3495 この機能の追加について • マイクロソフトがheapの実装で類似の機能を 用いている • reallocの、メモリの移動が発生しない場合の 挙動と同じsemanticsである • O(n)の操作をO(1)にできる • アロケータがresize_allocを提供しない場合、 bad_alloc()をthrowするため、追加の機能が必要と コンテナでそれをcatchしてallocate - move する処理のことだと思われる なる しかし、良いコンパイラはinline展開を行い、 さらに、このthrowとcatchを取り除く最適化を行う だ try { throw std::bad_alloc(); } catch (std::bad_alloc const&) が無くなるということか? ろう。 inline展開 光成さんの指摘、および、その後のML議論で、そのような最適化は現在行われていないことを確認 2014/1/30 https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/inplace/std-proposals/enjN4nBon4M/RIl4Rgh5bakJ 6
  7. 7. V N3495 この機能の追加について • Actually a big counter-argument, which I suspect is the cause for this not being in the c++11 standard in the first place: – CON: exact semantics not supported by the C standard, nor in new[]/delete[] operators, making an implementation for std::allocator hard. • C標準では、このsemacticsがサポートされていない reallocで、メモリアドレスそのままで伸長できない場合、メモリの移動が発生してしま う • new[], delete[] でもリサイズはできない • std::allocatorの実装が大変である 伸長できないとき、null ポインタを返すような、resizeみたいなものがあればいいのかな 後ほど、深掘りして議論する 2014/1/30 7
  8. 8. N3495 V 【参考】libsupc++ new_op.cc の実装 using std::new_handler; using std::bad_alloc; #if _GLIBCXX_HOSTED using std::malloc; #else // A freestanding C runtime may not provide "malloc" -- but there is no // other reasonable way to implement "operator new". extern "C" void *malloc (std::size_t); #endif _GLIBCXX_WEAK_DEFINITION void * operator new (std::size_t sz) _GLIBCXX_THROW (std::bad_alloc) { void *p; /* malloc (0) is unpredictable; avoid it. */ if (sz == 0) sz = 1; p = (void *) malloc (sz); while (p == 0) { new_handler handler = std::get_new_handler (); if (! handler) _GLIBCXX_THROW_OR_ABORT(bad_alloc()); handler (); p = (void *) malloc (sz); } return p; } 2014/1/30 8
  9. 9. V N3495 名前候補 • realloc – Cのライブラリ関数と同名で異なるセマンティックス のため却下 • realloc_inplace – 同上 • reallocate_inplace – 名前が長すぎるので却下 • alloc_resize – existing allocationをresizeするのでOK 振る舞いが提案の主題で、名前は2の次。良い名前Welcome 2014/1/30 9
  10. 10. N3495 V.1 サイズ拡張の成功率向上要因 • ASLR(Address Space Layout Randomization) – 今時の多くのアロケータは、ASLRを用いてい る – この結果、アロケートされたメモリブロック 間に 「2つの並行して行われる」というのは、あまり関係ない気がする 隙間が生じやすい • メモリの解放 – 2つの並行して行われるメモリアロケーション において、確保済みメモリが解放されること で、隙間が生じたり、拡がったりする。 2014/1/30 10
  11. 11. N3495 std::allocatorでalloc_resizeを実装 • Cとは全く別のアロケータ – Cとの共存時、効率が悪いのでNG • リサイズ可能かどうかを調べる、try_realloc みたいな関数をどこかに追加 – reallocを呼ぶまでに状態が変わるのでNG • リサイズ可能ならリサイズし、そうでなければ、 nullポインタを返すresize みたいな関数を どこかに追加 – Cのreallocの前半処理みたいなイメージ – よさげ? 2014/1/30 11
  12. 12. N3495 resizeをどこに追加する? • C標準ライブラリ – Cの規格改定に合わせて提案が必要 – Cユーザにメリットがあるか、不明 • C++では、move時にmemcpyでは困るという強い動機がある。 • C++標準ライブラリ 今回追加 – malloc, free, realloc との整合性が気になる 宣言済み – namespace std { using malloc; using free; using realloc; resizeの定義; } – resizeの実装を行うためには、C標準ライブラリの内部実装 (freelistとか)の知識が必要。同期してUpdateするなどメンテも必要。 • g++, clang++, VC++など全てCと合わせてリリースしているので問題は少ない? – C++規格で、resizeの説明を記述するのが、大変そう • mallocとかの詳細はC規格参照としつつ書けるかどうか。。。 2014/1/30 12
  13. 13. N3495 誤り指摘 • VI: Technical specifications XXX not the actual wording in the final standard, mostly intended to illustrate the proposed semantics. std::allocator may or may not implement std::allocator<T>::alloc_resize(pointer p, size_type n_cur, size_type n_new). If the combination (p, n_cur) does not reflect an existing allocation, an std::invalid_argument exception will be thrown. undefined behaviorの誤りだと思われる。 2014/1/30 13

×