පවරන්නෝ (C++)

C++ පරිගණක ක්‍රමලේඛනයෙහිදී, විබෙදන්නන් යනු සම්මත එකතුවෙහි වැදගත් සංරචකයකි. සම්මත එකතුව විසින් කන්ටේනර ලෙසින් පොදුවේ හැඳින්වෙන වන, ලැයිස්තුව සහ කුලකය වැනි, බොහෝ දත්ත ව්‍යුහ සපයයි. මෙම කන්ටේනර තුල පවතින පොදු ගති ලක්ෂණයක් වන්නේ ක්‍රමලේඛයේ සම්පාදනය තුලදී ඒවායේ තරම වෙනස් කර ගැනීමට ඇති හැකියාවය. මෙය සාක්ෂාත් කරගැනුම සඳහා, සාමාන්‍යයෙන් යම් ආකාරයක ගතික මතක විබෙදුමක් අවශ්‍ය වෙයි. විබෙදන්නන් දෙන ලද කන්ටේනරයක් සඳහා වන මතකය විබෙදුම සහ නිදහස් කිරීම(allocation and deallocation) වෙනුවෙන් ලැබෙන ඉල්ලීම් සියල්ල හසුරුවයි. C++ සම්මත එකතුව සාමාන්‍යයෙන් භාවිතා වන පොදු කාර්යය විබෙදන්නන් සපයන අතර ක්‍රමලේඛකයා(:en:programmer)ට තමන් නිර්මාණය කල විබෙදන්නන්ද සැපයිය හැක.

විබෙදන්නන් සම්මත අච්චු එකතුවේ(:en:Standard Template Library)(STL) කොටසක් ලෙස නිමවන ලද්දේ ඇලෙ‍‍‍ක්සැන්ඩර් ස්ටෙපනොෆ්(:en:Alexander Stepanov) විසිනි. ඒවා නිපදවීමේ අරමුණ වූයේ සම්මත එකතුව වඩාත් නම්‍යශීලී කිරීම සහ මතක ආකෘතියෙන් (memory model) නිදහස් කර ක්‍රමලේඛකයාට නිර්මාණය කරන ලද සූචක(pointer) සහ යොමු(reference) ආකාර සම්මත එකතුවත් සමඟ භාවිතා කිරීමට ඉඩ දීමටය. කෙසේ වෙතත් STL C++සම්මත(:en:C++ standard) යක් බවට පත්කිරීමේ ක්‍රියාවලියේදී, මතක ආකෘතිය සම්පූර්නයෙන්ම උපුටා ගැනීම(abstraction ) නිසා පිළිගත නොහැකි කාර්ය ඵල(performance) ප්‍රශ්න මතුවන බව C++ ප්‍රමිතිකරණ කමිටුවට අවබෝධ විය. මෙයට පිළියමක් ලෙස විබෙදන්නන්ගේ අවශ්‍යතාවය වඩාත් සීමා කරන ලදී. මෙහි ප්‍රතිඵලයක් ලෙස විබෙදන්නන් විසින් සපයන වෙනස්කම් කිරීමේ හැකියාව ස්ටෙපනොෆ්ගේ දැක්මෙහි වූවාට වඩා වැඩියෙන් සීමා වී තිබේ.

එහෙත්, වෙනස් කල විබෙදන්නන් අවශ්‍යය වන අවස්තා බොහෝ ඇත. වෙනස් කල හැකි විබෙදන්නන් අවශ්‍යය වීමට පොදු වූ හේතු කිහිපයක් නම් මතක සංසද(:en:memory pool) භාවිතා කර විබෙදුමේ කාර්ය ඵලය වර්ධනය කරගැනීම සහ පොදුවේ බෙදාගත් මතකය (:en:shared memory) හෝ එකතු කර ගත් අනවශ්‍යය(garbage-collected) මතකය වැනි විවිධ මතක ආකාර වලට ප්‍රවේශය සංක්‍ෂිප්තකරණයයි. සාමාන්‍යයෙන්, කුඩා ප්‍රමාණයේ මතකයන් බහුලව විබෙදන අවස්තාවලදී විශේෂ වූ විබෙදන්නෙක් සිටීම වාසිදායකය.

පසුබිම
ඇලෙ‍‍‍ක්සැන්ඩර් ස්ටෙපනොෆ්(:en:Alexander Stepanov) සහ මෙන්ග් ලී සම්මත අච්චු එකතුව(:en:Standard Template Library), C++(:en:C++) ප්‍රමිතිකරණ කමිටුවට 1994 වසරේ මාර්තු මාසයේදි ඉදිරිපත් කලේය.  සම්මත එකතුවට මූලික අනුමැතිය ලැබුනමුත් ගැටළු කිහිපයක් පැන නැගුනි. විශේෂයෙන් කන්ටේනර එකතුව මතක ආකෘතියෙන් (memory model) නිදහස් කර සාදන ලෙස ස්ටෙපනොෆ්ට උපදෙස් ලැබුනි.  මෙය විබෙදන්නන් නිර්මාණය කිරීමට හේතු විය. එහි ප්‍රතිඵලයක් ලෙස සියලුම STL කන්ටේනර අතුරු මුහුනත් විබෙදන්නන් පිළිගන්නා අයුරින් නැවත ක්‍රමලේඛනය කරන්නට සිදු විය.

STL C++ සම්මත එකතුව(:en:C++ Standard Library)ට එකතු කරන්නට වෙහෙස වුන කාලයේදී ඇන්ඩෘ කෝනින්ග්(Andrew Koenig) සහ බියානෙ ස්ට්‍රවුස්ටෘප්(:en:Bjarne Stroustrup) සමඟ එක්ව වැඩ කරන්නට ස්ටෙපනොෆ්ට අවස්ථාව ලැබුනි. 

කමිටුව මගින් ඒ දක්වා අනුමත නොවූ සමහර භාෂා ලක්ෂණ විබෙදන්නන් ගැනවූ මුල්ම යෝජනාව තුල අන්තර්ගත විය. මෙම ලක්ෂණ එවකට තිබූ කිසිඳු සම්පාදකය(:en:compiler)කින් සම්පාදනය කල නොහැකි වූ නිසා බියානෙ [ස්ට්‍රවුස්ටෘප්] සහ ඇන්ඩෘ [කෝනින්ග්] දෙදෙනාගේ කාලයෙන් වැඩි කොටසක් ගත වූයේ එම ලක්ෂණ නිවැරදිව භාවිතා කර ඇත්දැයි බැලීම සඳහායි. 

මතක ආකෘතිය සම්පූර්නයෙන්ම සංක්‍ෂිප්තකරණය ස්ටෙපනොෆ්ගේ අදහස වුවත්, එමගින් කාර්යක්ෂමතාව අඩුවීමේ අවදානමක් පවතින බව ප්‍රමිතිකරන කමිටුවට අවබෝධ විය.  මෙය වැලක්වීම සඳහා අමතර කාර්යයන් කිහිපයක් කිරීමට සිදු විය. විශේෂයෙන්, කන්ටේනර ක්‍රමලේඛනයේදී විබෙදන්නාගේ සූචක සහ අදාළ නිඛිලමය ආකාර(integral types) සඳහා වන ආකාර අර්ථ දැක්වීම(type definitions) සාමාන්‍යය(default) විබෙදන්නා සපයන ඒවාට සමාන බව උපකල්පනය කරන අතර දෙන ලද විබෙදන්නන් ආකාරයක නිදර්ශනය(instances ) සෑමවිටම සමාන ලෙස සංසන්දනය කරයි. මෙමගින් පළමු සැලැස්මේ අඩංගු වූ දේ ඵලදායී ලෙස වෙනස් කරන ලදී. විබෙදන්නන් ඵලදායී ලෙස භාවිතා කිරීමට නම් යොමු(references) වලට අදාලව භාෂාවේ අභ්‍යන්තර වෙනසක් සිදු කල යුතු බව ස්ටෙපනොෆ් පැවසීය. 

C++ සම්මතයෙහි 2011 සංශෝධනයට(2011 revision of the C++ Standard) අනුව දෙන ලද ආකාරයක විබෙදන්නන් සමාන ලෙස සංසන්දනය කරන සහ සාමාන්‍යය සූචක භාවිතා කිරීමට අවශ්‍යය මුගටි වචන (weasel words) ඉවත් කර ඇත. මෙමගින් විබෙදන්නන් වඩාත් ප්‍රයෝජනවත් ලෙස භාවිතා කිරීමට අවස්ථාව ලැබී ඇත. සංශෝධිත සම්මතයන්ට අනුව විබෙදන්නන්ගේ C++ ආමන්ත්‍රණ ආකෘතීන්(C++ address model)වලට ව්‍යාප්තවීම පෙන්වීමේ හැකියාව ඉවත් කර ඇත.

අවශ්‍යතා
ඕනෑම විබෙදන්නෙකුට අවශ්‍ය දේවල් සහිත සරණිය(class)ක්, විබෙදන්නෙක් ලෙස භාවිත කල හැක. විශේෂයෙන්, T ආකාරයේ වස්තුවකට මතකය විබෙදා දීමේ හැකියාවකින් යුක්ත වීමට සරණියක් A වස්තූන් පොදුවේ ප්‍රකාශ කිරීමේදී සහ T ආකාරයේ වස්තූන් වෙත යොමු හෝ සූචක ප්‍රකාශ කිරීම සඳහා A::pointer, A::const_pointer, A::reference, A::const_reference, සහ A::value_type ආකාර සැපයිය යුතුය. එමෙන්ම A::size_type ආකාරයේ, A ලෙස අර්ථ දක්වන ලද විබෙදන ආකෘතියක වස්තුවකට තිබිය හැකි විශලතම තරම නිරූපනය කල හැකි නිලකුණු ආකාරයක් සැපයිය යුතුය. තවද, විබෙදන ආකෘතියේ සූචක)(pointer)  2ක් අතර වෙනස නිරූපනය කල හැකි ලකුණක් සහිත නිඛිලමය(integral) A::difference_type ආකාරයක්ද සැපයිය යුතුය. 

එහෙත් සම්මත එකතු ක්‍රමලේඛනයේදී විබෙදන්නන්ගේ A::pointer සහ A::const_pointer යනු T* සහ T const* හි ආකාර අර්ථ දැක්වීම(:en:typedef) ලෙස උපකල්පනය කරයි, පොදු විබෙදන්නන්ව අනුමත කිරීමට එකතු ක්‍රමලේඛකයන්ව දිරිමත් කර ඇත.

A විබෙදන්නෙකුට T ආකාරයේ වස්තු සඳහා A::pointer A::allocate(size_type n, A<void>::const_pointer hint = 0) මුද්‍රාව සහිතව සාමාජික ශ්‍රිතයක් පැවතිය යුතුය. මෙහි ඵලය විබෙදූ T ආකාරයේ වස්තු n ප්‍රමාණයක් සහිත අරාව(array)ක පළමු අංගයේ සූචකය ලැබේ; මතකය පමණක් විබෙදේ, වස්තූන් නොසෑදේ. තවද, යොමු ප්‍රදේශය(locality) වර්ධනය කිරීම සඳහා මතක විබෙදුම සිදුවිය යුතු ස්ථානය ගැන ඉඟියක් ලෙස අනවශ්‍ය සූචකයක්(A මගින් විබෙදූ වස්තුවක් දක්වන) භාවිතා කල හැක.

අනුරූප void A::deallocate(A::pointer p, A::size_type n) සාමාජික ශ්‍රිතය, A::allocate ශ්‍රිතයේ මුල් ආයාචනයේ(invocation) ඵලයක් වන ඕනෑම සූචකයක් සහ නිදහස් කිරීමට අවශ්‍යය අංග ගණන පිළිගනී. A::max_size() යන සාමාජික ශ්‍රිතයේ ඵලය වන්නේ A::allocate ශ්‍රිතයේ ආයාචනයෙන්(invocation) සාර්ථකව විබෙදෙන T ආකාරයේ උපරිම වස්තු සංඛ්‍යාවයි. සාමාන්‍යයෙන් ඵලය ලෙස ලැබෙන අගය A::size_type(-1) / sizeof(T) ආකාර වේ. තවද, A::address යන සාමාජික ශ්‍රිතයට A::reference දුන් විට ඵලය ලෙස වස්තුවකට ආමන්ත්‍රණයේ(address) සූචකය A::pointer ලැබේ.

වස්තු නිර්මාණය හා විනාශ කිරීම, විබෙදුම හා නිදහස් කිරීම යන ක්‍රියාවලදී වෙනමම සිදුවේ. විබෙදන්නා සතුව වස්තු නිර්මාණය හා විනාශ කිරීම උදෙසා සාමාජික ශ්‍රිතයන් 2ක් පැවතිය යුතුය. පිළිවෙලින් A::construct සහ A::destroy ශ්‍රිතයේ අර්ථ විචාරය පහත ආකාර විය යුතුය.
template <typename T>
void A::construct(A::pointer p, A::const_reference t) { new ((void*) p) T(t); }

template <typename T>
void A::destroy(A::pointer p){ ((T*)p)->~T(); }
ඉහත කේතය, placement new යන කාරක රීති භාවිතා කිරීම සහ destructor යන්න කෙලින්ම ආමන්ත්‍රණය කරයි.

නිර්මාණය කල විබෙදුම්
කාර්ය ඵලය වැඩිකර ගැනීම සහ මතකය භාවිතය දියුනු කර ගැනීම නිර්මාණය කල විබෙදුම් භාවිතා කිරීමේ අරමුණයි. සාමාන්‍යය විබෙදුම් මතකය විබෙදීමට operator new භාවිතා කරයි. සාමාන්‍යය විබෙදුම C heap allocation functions වටා සිහින් තීරයක් ලෙස ක්‍රමලේඛනගත කර ඇත, මෙය විශාල කොටස් ලෙස මතකය විබෙදන කන්ටේනර(vector සහ :en:deque ) වලට සාර්ථක වුවත්, කුඩා ප්‍රමාණයන්ගෙන් නිතර මතකය විබෙදන කන්ටේනර(map සහ list) වලට මෙමගින් මතකය විබෙදීම සාමාන්‍යයෙන් සෙමින් සිදුවේ.

කාර්ය ඵලය වැඩි කිරීමේ ප්‍රසිද්ධ ක්‍රමයක් නම් මතක සංසද(:en:memory pool) පදනම් කරගත් විබෙදන්නෙක් නිර්මාණය කිරීමයි. මෙහිදී එක්වරම මතකයෙන් විශාල ප්‍රමාණයේ කොටසක් වෙන්කෙරේ. නිර්මිත විබෙදන්නා සෑම විබෙදුමකදීම මතක සංසදයට සූචකයක් ඵලය ලෙස සපයයි. මතක සංසදය තුළ ආයුකාළය(lifetime) අවසන් වන විට මතකය නිදහස් වීම සිදු වේ. මතක සංසද පදනම් කරගත් විබෙදන්නෙක්ට උදාහරනයක් මෙහි ඇත.:en:Boost C++ Libraries

මතකය පාදක වූ වැරදි නිවැරදි කිරීම(:en:debugging) සඳහා යොදා ගැනීම නිර්මිත විබෙදන්නන්ගේ තවත් ප්‍රයෝජනයකි. වැරදි නිවැරදි කිරීමට අදාල තොරතුරු(debugging information) ගබඩා කරගැනීමට අමතර මතකයක් වෙන් කරන විබෙදන්නෙක් නිර්මාණය කර මෙය සිදු කල හැක.

භාවිත
සම්මත කන්ටේනරයක් භාවිතා කරන විට, සාමාන්‍යයෙන් std::allocator<T>: වන අච්චුව(template)ක් හරහ විබෙදන්නා හඳුන්වයි.
namespace std {
  template <class T, class Allocator = allocator<T> > class vector;
// ...
අනෙක් සියලුම සරණි අච්චු මෙන්ම සම්මත අච්චු එකතුවේ ඇති එකිනෙකට වෙනස් විබෙදුම් පරාමිතීන් සහිත කන්ටේනර වල අවස්ථා(instantiations)ද එකිනෙකට වෙනස් වේ. std::vector<int> පරමිතියක් අපේක්ෂාවෙන් සිටින ශ්‍රිතයක් vector ආකාරය පමණක් පිළිගනී.

:en:C++11 හි විබෙදන්නන්ට කල සංශෝධන
නවතම C++ සම්මත අනුව විශයපථ(scoped) විබෙදන්නන්ට ඉඩ ලබා දෙන ලෙස විබෙදුම් අතුරු මුහුණත වැඩි දියුනු කර ඇත. එම නිසා දාමයක්(nested) ලෙස මතකය විබෙදීමට අවශ්‍යය කන්ටේනර වලට ඔවුන්ගේ විබෙදන්නාගෙන්ම මතකය වෙන්කල හැක.

යොමුව

බාහිර සබැඳි
CodeGuru: Allocators (STL).
An introductory article "C++ Standard Allocator, An Introduction and Implementation".
A custom allocator implementation based on malloc

C++ Standard Library
Generic programming
Articles with example C++ code