堎所ずルヌル host newを䜿甚しおC ++コヌドを最適化する





オブゞェクトの埌にオブゞェクトを䜜成する堎合、動的メモリ割り圓おなどの「些现なこず」に泚意を払わないこずがよくありたす。 コピヌずシリアル化に加えお、ヒヌプから新しいメモリを割り圓おるず、C ++の速床の利点が埐々に無効になりたす。 倧切な新しいものをより集䞭的に䜿甚すればするほど、メモリが䞍足し、断片化され、あらゆる方法でリヌクが発生するため、アプリケヌションにずっおは難しくなりたす。 䟿利ですが、パフォヌマンスSTLコンテナヌには暗黙的に危険です。ベクタヌ、ストリング、デック、マップは、すでにこの運呜に陥っおいたす。 倧量の小さなオブゞェクトの割り圓おの速床を萜ずすのは特に残念です。 しかし、スタック䞊のそのようなオブゞェクトのメモリの配眮を凊理する方法がありたすが、特別なデヌタクラスで実装の詳现を隠したす。 これは、新しい配眮のメカニズムに圹立ちたす。これは、ヒヌプから頻繁か぀少量のメモリ割り圓おでいっぱいのアプリケヌションを最適化するための比類のない方法です。



前回のレッスンでは、驚くべきこずを行いたした。実行時に蚈算され、動的に入力される型の倀を含むコンテナずしおC ++オブゞェクトを操䜜したした。 オブゞェクトぞの入力時に、実際のデヌタ型を参照するstd :: shared_ptrを介しおコピヌオンラむトアドオンを積極的に䜿甚したした。 たた、任意のデヌタ初期化にメモリを動的に割り圓お、任意の型の新しいデヌタが必芁になるたびにnewを呌び出すこずも理解されたした。



このアプロヌチには利点がありたす。 デヌタは耇数のオブゞェクト間で共有され、コピヌが遅延する可胜性がありたす。 原則ずしお、デヌタ型に぀いお事前に䜕も知るこずはできたせん。 ただし、この方法には倚くの欠点もありたす。これは、非垞に倧きい可胜性のあるオブゞェクトに察しお、コピヌオンラむトが原則ずしお䜿甚されるためです。



最初の欠陥はすぐに明らかになりたす。 倧量の動的メモリ割り圓おは、プログラム実行、特にnewを介した倧量の暗黙的なメモリ割り圓おを倧幅に遅くしたす。 はい、std :: stringずstd :: vectorの䞡方を知っおいたす。倚くの堎合、プログラマに確認するこずなく、メモリの再割り圓おを開始し、次々ず新しいものを呌び出したすそしお、std :: vectorぞのデヌタの移動に぀いおも説明したす。 C ++開発の優れた専門家は、暙準コンテナのこれらの面癜い機胜を垞に知っおおり、新しいメモリセグメントを割り圓おるための䞍必芁な費甚を回避する方法を理解しおいたす。 玔粋なCが垞に適しおいるのは、メモリを䜿甚した䜜業が透過的に実行されたためです。C++では、メモリを䜿甚した暗黙的な䜜業のすべおのケヌスを垞に念頭に眮く必芁がありたす。



2番目の欠点は最初の欠点です。 メモリの小さなセグメントを倧量に頻繁に割り圓おるず、メモリのひどい断片化が発生し、たずえば同じstd ::ベクタヌたたはstd ::文字列を初期化するために、かなり小さなメモリブロックを1぀のピヌスに割り圓おるこずができなくなりたす。 その結果、明らかな理由もなくbad_allocを取埗したす。 必芁以䞊のメモリがありたすが、メモリが非垞に断片化されおいる状況では、小さなサむズの連続ブロックを割り圓おるこずはできたせん。



したがっお、スタックに簡単に配眮できるint64_tに匹敵する小さなオブゞェクトには、別のデヌタ凊理技術を䜿甚できたす。 このようなオブゞェクトは倀枡しできたす。1぀たたは2぀のレゞスタが簡単にコピヌされるため、最初の倉曎たで遅延するこずなく、䜕床でもコピヌできたす。



同時に、実装時にデヌタの詳现を宣蚀する慣行から逞脱するべきではありたせん。 ただし、䜕かを犠牲にする必芁がありたす。デヌタの正確なサむズをバむト単䜍で事前に知る必芁がありたす。 通垞のデヌタポむンタず䞀緒にオブゞェクトデヌタを配眮するために、クラスにバッファを保持するために必芁になりたす。 より詳现に。



ファヌストクラス



倖偎では、ほずんど䜕も倉わりたせん。 APIオブゞェクトを提䟛するすべおの同じクラス。 このクラスには、前方宣蚀によっお宣蚀されたクラスのデヌタぞのリンクが含たれおおり、実装の詳现でレンダリングされたす。 このため、クラスフィヌルドにこの型のオブゞェクトを宣蚀するこずはできたせんが、単玔なポむンタヌでデヌタ型を参照し、同じオブゞェクトにオブゞェクトデヌタを栌玍するためのバッファヌを事前に蚭定できたす。 たずえば、スタック䞊にオブゞェクトが䜜成された堎合、すべおのデヌタはオブゞェクトの䞀郚ずしおスタックに保存されたす。 次に、すべおが適切に配眮されるように䟋を考えたす。



class object { public: ... protected: //    class data; //       static const size_t max_data_size = N; private: //    data* m_data; //  ,     char m_buffer[max_data_size]; };
      
      





このコヌドでは、実装でデヌタを隠すずいうむデオロギヌを続けおいたす。クラスデヌタに぀いお知っおいるのは、クラスの名前ずデヌタぞのポむンタヌの存圚だけです。 ただし、珟圚はヒヌプ内でメモリ䞍足を回避する機䌚がありたす。 C ++の甚語では、クラスはフィヌルドの圢匏でデヌタを保存したす。 実際、デヌタはm_bufferバッファヌに配眮されたす。m_bufferバッファヌは、クラスが䜜成されたずきに既に割り圓おられたメモリです。 バむトバッファにデヌタを配眮する方法の詳现を説明するだけです。



新しいホスティング



原則ずしお、䜜成されたオブゞェクトを配眮するための既補のメモリ領域を指定する機胜ずしお、new挔算子のこのような有甚なプロパティを考える人はほずんどいたせん。 必芁なのは、割り圓おられたバッファに任意のタむプのオブゞェクトを䜜成するために、新芏m_bufferを曞き蟌むこずだけです。 簡単に聞こえたすが、最倧バッファサむズを事前に指定するずいう高い䟡栌を支払うこずを芚えおおく必芁がありたす。 それだけでなく、バ​​ッファのサむズはヘッダヌファむルに収たり、API宣蚀に明瀺的に関䞎したす。



しかし、我々はスピヌドで勝ちたす。 初期化ごずにヒヌプにデヌタを割り圓おるこずで、Javaに遅れをずるリスクが発生した堎合、すべおのデヌタをスタックに配眮するこずで、玔粋なsi速床C ++を陀くほずんどすべおの高レベル蚀語で達成䞍可胜な速床が埗られたす。 同時に、抜象化のレベルは非垞に高く、通垞のC ++オブゞェクトにAPIを構築し、実装の詳现を隠したす。 唯䞀の制限は、蚭定したサむズです。 実装内のデヌタクラスのフィヌルドセットを簡単に倉曎するこずはできなくなりたした。サむズを垞に芚えおおく必芁がありたす。 さらに、実装に蚘述されおいるデヌタのサむズをチェックしお、ヘッダヌファむルで指定されおいるデヌタに準拠する必芁がありたす。 ラむブラリのアセンブリがヘッダヌファむルのバヌゞョンず異なる堎合があるのは、たずえばさたざたな゜ヌスから受信する堎合などです。 そのようなチェックが、newを配眮するこずによっお準備されたメモリにオブゞェクトを䜜成するように芋える方法の䟋を芋おみたしょう。



 object::object() : m_data(new(m_buffer) object::data) { static_assert(sizeof(object::data) <= max_data_size, "..."); }
      
      





ここで、static_assertはコンパむル段階で実際に実行されるため、m_dataはオブゞェクト::デヌタ甚にm_bufferバッファヌに十分なメモリがある堎合にのみ初期化されたす。 同様に、オブゞェクトクラスの䞋䜍クラスたずえば、flowerでは、デヌタが基本クラスの実装に栌玍されるため、デヌタが指定されたバヌを超えおはなりたせん。



 flower::flower(std::string const& name) : object(new(get_buffer()) flower::data(name)) { static_assert(sizeof(flower::data) < max_data_size, "..." ); }
      
      





明らかに、これには、オブゞェクト::デヌタ*からオブゞェクトの保護されたコンストラクタヌず同様に、基本クラスのm_bufferアドレスを取埗するためにget_bufferprotectedメ゜ッドが必芁です。 前のリリヌスのように、基本クラスのデヌタから盞続人のデヌタを継承するため、flower :: data *はobject :: data *ず互換性がありたす。 セキュリティのために、object :: data *から基本コンストラクタに远加する䟡倀がありたす。以前に割り圓おられたバッファのアドレスが枡されるこずを確認したす。



 object::object(object::data* data_ptr) { if (static_cast<void*>(data_ptr) != static_cast<void*>(m_buffer)) throw some_exception(...); m_data = data_ptr; }
      
      





その結果、以前ず同様に、通垞のクラスオブゞェクトを操䜜するこずで動的型付けを゚ミュレヌトできたす。 たずえば、次のように



 object rose = flower("rose");
      
      





倧きなデヌタオブゞェクト



デヌタサむズが指定された最倧倀を超えるオブゞェクトをどうするかを芋぀けるこずは残っおいたす。 実際、ここのすべおは非垞に簡単です。 copy_on_write <data :: impl>のサむズが制限に収たるだけで十分です。これは、本質的にstd :: shared_ptr <data :: impl>のアドオンです。ここで、implは任意のサむズのデヌタ​​クラスの実装です。 std :: shared_ptr <data :: impl>のサむズは、data :: implクラス自䜓のオブゞェクトのサむズに䟝存しないため、倀によるストレヌゞから参照によるストレヌゞぞの移行でデヌタを栌玍する普遍的な方法を取埗したす。



 class huge { public: ... protected: class data; }; class huge::data { public: ... protected: class impl; private: copy_on_write<impl> m_impl; };
      
      





ただし、動的型付けを䜿甚するオブゞェクト甚の単䞀APIの問題の解決策から脱华し、新しい配眮による最適化の別の䟋を考えおみたしょう。



copy_on_write ::フラッシュバック



誰かが以前のリリヌスをスキップした堎合、copy_on_writeクラスはコピヌ最適化でデヌタを保存するためのテンプレヌトクラスです。 ポむンタヌを゚ミュレヌトするこのクラスには、constおよびnon-constの堎合のトリッキヌなoperator->オヌバヌロヌドがありたす。 オブゞェクトをコピヌするずき、高䟡なコピヌを匕き起こすこずなく同じデヌタを参照したす。 ただし、デヌタを朜圚的に倉曎するデヌタクラスの非定数メ゜ッドを呌び出すずすぐに、珟圚のオブゞェクトのデヌタのコピヌをデタッチしたす。 簡玠化された実装は次のようになりたす。



 template <typename impl_type> class copy_on_write { public: copy_on_write(impl_type* pimpl) : m_pimpl(pimpl) { } impl_type* operator -> () { if (!m_pimpl.unique()) m_pimpl.reset(new impl_type(*m_pimpl)); return m_pimpl.get(); } impl_type const* operator -> () const { return m_pimpl.get(); } private: std::shared_ptr<impl_type> m_pimpl; };
      
      





したがっお、組み蟌みバッファの最倧デヌタサむズを遞択する堎合、フィヌルドずしおcopy_on_writeを含むクラスのサむズを考慮する䟡倀がありたす。


デヌタフィヌルド



ホストnewを介しお最適化する最も匷力な方法は、SQLク゚リの遞択レコヌドのフィヌルドを䜿甚するこずです。 サンプルは、敎数や実数から文字列や配列たで、さたざたなタむプのデヌタセットを芁求したす。 デヌタ自䜓は動的に取埗され、デヌタベヌス偎から取埗されたフィヌルドタむプは動的型付け゚ミュレヌションで初期化する必芁がありたすが、すべおのレコヌドには、各レコヌドの合蚈デヌタサむズを決定できる同じフィヌルドタむプのセットが含たれおいたす。 これにより、レコヌドフィヌルドにメモリを1回だけ割り圓おるこずができ、遞択した各レコヌドに含たれるフィヌルドのタむプに応じおサむズが蚈算されたす。 たた、単䞀のナニットずしおすべおのレコヌドに䞀床メモリを割り圓おるこずも可胜ですが、原則ずしお、レコヌドを取埗した埌、フィルタリングや䞊べ替えを含むあらゆる皮類の操䜜が実行されるため、埌続の操䜜の䟿宜のためにレコヌド自䜓をコピヌオンラむトオブゞェクトずしお蚘述するこずは理にかなっおいたす。 各フィヌルドにヒヌプからメモリを割り圓おるのは䞍圓に高䟡です。



これは、宣蚀を単玔化し、デヌタクラスから盎接copy_on_writeを䜿甚した堎合のレコヌドクラスの倖芳です。



 class record { public: record(std::vector<field::type> const& types); ... protected: class data; private: copy_on_write<data> m_data; }; class record::data { public: data(std::vector<field::type> const& types); ... private: std::vector<char> m_buffer; std::vector<field*> m_fields; };
      
      





ここでは、説明を簡単にするために、フィヌルドタむプのベクトルstd :: vector <field :: type>、enum倀の配列が導入されおいたす。 実際、この配列は、boost :: fusionを介しお匕数から型指定するか、Boost.Preprocessorを䜿甚しお、任意の型の匕数から型オブゞェクトの汎甚オブゞェクトの配列をダむダルする必芁がありたす。 各レコヌドのヒヌプからメモリを単䞀に割り圓おるメカニズムは、今では重芁です。



 record::data::data(std::vector<field::type> const& types) : m_buffer(field::calc_size(types)), m_fields(types.size()) { size_t offset = 0; std::transform(types.begin(), types.end(), m_fields.begin(), [&offset](field::type type, field*& field_ptr) { field_ptr = new(m_buffer + offset) field(type); offset += field::size(type); } ); }
      
      





ここで、field :: sizeは枡されたfield :: typeからデヌタのサむズを蚈算し、field :: calc_sizeはすでにstd :: vector <field :: type>ずしお枡されたレコヌドタむプのセット党䜓に必芁な合蚈サむズを蚈算しおいたす。



フィヌルドフィヌルドは、基本的に動的コンテンツのコンテナであるオブゞェクトタむプず同様に実装されたす。 ほずんどの型int64_t、bool、doubleはスカラヌであり、倀によっお栌玍されたす。 std ::文字列型も倀で保存できたすが、文字列デヌタがほが確実にヒヌプに保存され、動的に割り圓おられるこずを考慮する䟡倀がありたす。 特定の長さの特定のvarcharをサポヌトする堎合、ほずんどの堎合、固定長の文字の配列を持぀独自の型copy_on_writeが必芁になりたす。



さたざたなタむプのフィヌルドは、オブゞェクトクラスから継承されたさたざたなタむプのオブゞェクトに䌌おいたす。 enumを䜿甚するこずもできたせんが、型に盎接結び付けられたすが、原則ずしお、SQLク゚リの結果を解析するには、すべおのフィヌルド型が事前にわかっおいるデヌタのバむトパケットを逆シリアル化する必芁がありたす。したがっお、enumには制限がありたせん。 さらに、メタプログラミングは気匱な人向けではないため、ここではMPLずBoost.Fusionを怜蚎したせん。



新しいホストを䜿甚する最埌の重芁な偎面、぀たりC ++の同じタむプのオブゞェクトのプヌルに぀いおは觊れおいたせん。



同じタむプのオブゞェクトのプヌル



前ず同様に、動的メモリ割り圓おを最適化しおいたす。 オブゞェクトプヌルずは䜕ですか これは、特定のタむプを初期化するために倧勢の人によっお事前に割り圓おられたブランクの配列です。 ある意味では、䞊蚘のレコヌドはフィヌルドオブゞェクトのプヌルでした。 たた、高レベル蚀語C、Python、Javaで䜜業しおいる堎合、オブゞェクトのプヌルに出䌚った可胜性がありたす。これらは、準備されたメモリセグメントを䜿甚しお、オブゞェクトを配眮する新しいオブゞェクトを割り圓おたす。実際には、タむプはオブゞェクトです。 プヌルオブゞェクトの1぀が䞍芁になった埌、぀たり、参照されなくなった埌、すぐに初期化解陀されるか、ガベヌゞコレクタヌ、ガベヌゞコレクタヌ、所有者のいない商品を削陀するための特別なメカニズムの次のバむパスの圢で悲しい運呜を埅っおいたす。 䞀般的に、プヌル内のオブゞェクトの初期化解陀はその匱点です。 しかし、通垞はすでに初期化されおいるか、初期化の準備ができおいるオブゞェクトの迅速な遞択を取埗したす。 オブゞェクトタむプに基づいお、参照カりントによる初期化解陀ずガベヌゞコレクタヌを備えた本栌的なオブゞェクトプヌルを䜜成するず、JavaたたはPythonが埗られたす。 そのようなものが必芁な堎合、庭を囲い、ごみ収集で既補の蚀語を取るべきではないでしょうか ただし、同じタむプのオブゞェクトの最適化のために、事前に倧量のメモリセグメントを割り圓おる必芁があり、タスクが実際に特定の基本クラスを持぀倚数のオブゞェクトの倧量初期化を必芁ずする堎合、オブゞェクトのプヌルにより、倧量の動的メモリ割り圓おを回避できたす。



理解するには、明確で応甚的な説明が必芁です。 レコヌドのプヌルを䜿甚したSQLク゚リの結果ずしお実際にフェッチするのはどうですか これにより、サンプルレコヌドオブゞェクトを構築するためのメモリ割り圓おの質量が最適化されたす。



 class selection { public: selection(std::vector<field::type> const& types, size_t row_count); ... protected: class data; private: copy_on_write<data> m_data; }; class selection::data { public: data(std::vector<field::type> const& types, size_t row_count); ... private: std::vector<field::type> m_types; std::vector<char> m_buffer; std::vector<record> m_rows; }; selection::data::data(std::vector<field::type> const& types, size_t row_count) : m_types(types) { if (!row_count) return; m_rows.reserve(row_count); size_t row_data_size = field::calc_size(types); m_buffer.resize(row_count * row_data_size); char* offset = m_buffer for (size_t i = 0; i < row_count; ++i) { m_rows.push_back(record::inplace(offset, types)); offset += row_data_size; } }
      
      





record :: inplaceは、本質的に、ヒヌプではなく、指定されたアドレスにレコヌドデヌタを䜜成したす。



 record record::inplace(void* address, std::vector<field::type> const& types) { return record(new(address) record::data(types)); }
      
      





初期化ず特別なデストラクタを備えたレコヌドコンストラクタが必芁です。詳现は埌で説明したす。 レコヌドを初期化するこのオプションにより、以前のバヌゞョン、぀たりcopy_on_writeフィヌルドのみを含むクラスの圢匏でレコヌドを䜿甚するこずができなくなりたす。 ヒヌプ䞊のデヌタの動的な割り圓おに冷静に頌っお、必芁に応じおレコヌドを切り替えるこずはできたせん。 䞀方、倧芏暡なデヌタセットを䜿甚するず、パフォヌマンスが倧幅に向䞊したす。 ただし、新しい投皿には泚意が必芁なキャッチがありたす。



明瀺的なデストラクタ呌び出し



è­Šå‘Š



誰かが最埌たで読んだり、斜めに読んだりしない習慣がある堎合-非垞に無駄です。 この重芁なセクションをスキップするこずで、メモリリヌク倧量のメモリリヌクを発生させるこずができたす。


ホストnewを䜿甚する堎合、もう1぀「しかし」-削陀は䜕もしないので、デストラクタを手動で呌び出す必芁がありたす。 したがっお、事前に準備されたメモリに割り圓おられたデヌタを含むクラスは、デストラクタ内のメモリに䜜成されたクラスのデストラクタを明瀺的に呌び出す必芁がありたす。 したがっお、クラスデストラクタオブゞェクト::〜オブゞェクトは、オブゞェクト::デヌタ::〜デヌタデストラクタを明瀺的に呌び出す必芁があり、レコヌド::デヌタ::〜デヌタデストラクタは、フィヌルドごずに1぀のフィヌルド::〜フィヌルドデストラクタを呌び出す必芁がありたす。 これがどのように発生するかを明確に瀺すために、オブゞェクトクラスをより詳现に説明したす。



 class object { public: object(); virtual ~object(); ... protected: class data; char* get_buffer(); object(data* derived_data); static const size_t max_data_size = N; private: data* m_data; char m_buffer[max_data_size]; }; object::object() : m_data(new(m_buffer) data) { static_assert(sizeof(data) <= max_data_size, "..."); } object::~object() { m_data->~data(); }
      
      





デヌタクラスのデストラクタは仮想ずしお蚘述する必芁があるため、object :: dataの継承者が䜿甚されおいるかに関係なく、デヌタの初期化解陀は成功したす。



たた、コンストラクタヌずコピヌ挔算子、および移動を再定矩する必芁がありたす。これは、自動生成されたコンストラクタヌに満足したcopy_on_writeの堎合ずは異なり、ここでは各オブゞェクトが単玔なポむンタヌでデヌタ領域を参照するためです。 したがっお、デフォルトの動䜜を修正したす。



 object::object(object const& another) : m_buffer(max_data_size), m_data(another.clone_data_at(m_buffer)) { } object& object::operator = (object const& another) { destruct_data(); //     m_data = another.clone_data_at(m_buffer); return *this; } object::data* object::clone_data_at(void* address) { return m_data->clone_at(address); } //      //      object::data* object::data::clone_at(void* address) { return new(address) data(*this); } void object::destruct_data() { m_data->~data(); }
      
      





ここでは、新しいdesctuct_dataメ゜ッドがデストラクタオブゞェクト::〜オブゞェクトで芁求されおいたす。 䞀床尋ねるず、圌のための堎所があるこずを意味したす。 コンストラクタヌず移動挔算子の堎合、動䜜は同様です。



 object::object(object&& another) : m_data(another.move_data_to(m_buffer)) { } object& object::operator = (object const& another) { destruct_data(); //     m_data = another.move_data_to(m_buffer); return *this; } object::data* object::move_data_to(void* address) { return m_data->move_to(address); } //      //      object::data* object::data::move_to(void* address) { return new(address) data(std::move(*this)); } object::~object() { destruct_data(); }
      
      





したがっお、メモリリヌクの危険性はなくなりたす。 APIナヌザヌは萜ち着いお開発できたす。



ヒヌプ䞊の新芏ホストず新芏ホストのホスティング



既にお気付きのように、host newを䜿甚するクラスは実装がはるかに困難です。 準備されたメモリにオブゞェクトを配眮する手法で実装されたクラスを䜿甚するすべおの偎面を培底的にテストする必芁がありたす。 通垞、クラスの通垞の新しいものの耇雑さは、スマヌトポむンタヌをラップするこずになりたす。 次に、デヌタ型の最倧サむズを明瀺的に指定するこずで動的型付けの゚ミュレヌションでさえ耇雑になる堎合、どのような利点がありたすか



速床の向䞊。 より䟿利なC、Java、Pythonず比范したC ++の力は、実行速床にありたす。 ここでは、新しいオブゞェクトのヒヌプに移動しないため、最高速床に達したす。 たた、メモリの断片化を回避しお、将来アプリケヌションの速床を萜ずさないでください。 断片化された蚘憶はチヌズのようなものです。穎がいっぱいで、これらの穎の倧きさでオレンゞを詰め蟌むこずができたすが、実際にはオレンゞはどの穎にも収たらず、それぞれが小さすぎたす。 そのため、連続メモリのセグメントを必芁ずするstd :: vectorおよびstd :: stringは、芁玠を再配垃するずきにい぀かstd :: bad_allocを取埗できたす。



暙準ラむブラリの新しいホスティング



蚘事の冒頭でstd :: vectorにnewを配眮するこずをお玄束したしたか そのため、std :: vectorのすべおの芁玠コンストラクタヌは、準備されたメモリで呌び出されたす。 たた、デストラクタは芁玠に察しおも積極的に呌び出されたす。 これは、intやcharなどの単玔なPOD型のベクタヌでは重芁ではありたせんが、std :: vectorを匷調したい堎合、customに重芁なデフォルトコンストラクタヌずそれほど重芁ではないコピヌコンストラクタヌがある堎合、そうしないず倚くの問題が発生したすstd :: vectorがそのデヌタをどのように凊理するかを理解したす。



では、ベクタヌにサむズ倉曎を芁求するずどうなりたすか たず、ベクタヌは必芁なバむト数をただ予玄しおいないように芋えたすベクタヌは垞にマヌゞン付きのバッファヌを割り圓おたす。その埌、新しいバッファヌを割り圓おたす。 すべおの既存の芁玠は、移動コンストラクタヌによっお、察応するアドレスにnewを配眮するこずにより、新しいバッファヌに転送されたす。 その結果、すべおの芁玠が配眮されたす。 その埌、ベクトルは必芁な数の芁玠を配列の最埌たで取埗し、新しいデフォルトのコンストラクタヌを配眮しお各芁玠を䜜成したす。 たた反察方向-芁玠の数を枛らすず、芁玠を削陀するずきにデストラクタが「手動で」発生したす。



std :: vectorずは異なり、std :: stringコンテナは、コンストラクタやデストラクタを必芁ずしないcharを垞に栌玍するずいう理由だけで、新しい配眮を凊理したせん。 ただし、暙準ラむブラリの倚くのコンテナdeque、list、map、および任意のデヌタを栌玍するためのその他のクラステンプレヌト-実装の新しいホスティングを積極的に䜿甚したす。



newをハックのようなものず考える必芁はありたせん。指定されたメモリのコンストラクタでオブゞェクトを初期化できる本栌的な蚀語機胜です。 この操䜜は、割り圓おられたバむトブロックが特定のタむプ通垞は構造䜓ぞのポむンタヌずしお宣蚀され、このメモリブロックでのさらなる䜜業がこのタむプのAPIによっお実行された、叀いC蚀語のトリックに䌌おいたす。



結果は䜕ですか



もちろん、必芁に応じお新しいホスティングを䜿甚する機胜は、それが本圓に必芁な堎合にのみ、効率的か぀正圓な理由で、すぐには実珟したせん。 それらのいく぀かは、予備的な最適化の害によっお最埌たで打ち負かされおいたすが、反察に、他の人は、蚘事を読んだ埌に、必芁な堎所ず必芁でない堎所に新しいm_bufferを埋め蟌むように急ぎたす。 時間が経぀に぀れお、䞡方が黄金色になりたす。



メ゜ッドの本質は単玔です-クラスオブゞェクトを準備されたメモリに配眮するこずが可胜であり、必芁な堎合、いく぀かの単玔なルヌルを芚えおいれば、これを行うのは比范的簡単です。





他のすべおは、開発者の正確さず無限の想像力によっおのみ制限されたす。 それはあなたです。



画像



Hacker Magazine190で最初に発行されたした。

投皿者Vladimir Qualab Kerimov 、リヌディングC ++開発者、Parallels



ハッカヌを賌読する




All Articles