වස්තුවට වඩා මා දර්ශකයක් භාවිතා කළ යුත්තේ ඇයි?


1620

මම ජාවා පසුබිමකින් පැමිණ C ++ හි ඇති වස්තූන් සමඟ වැඩ කිරීමට පටන් ගෙන ඇත. නමුත් මට සිදු වූ එක් දෙයක් නම්, මිනිසුන් බොහෝ විට වස්තූන්ට වඩා වස්තූන් සඳහා දර්ශක භාවිතා කිරීමයි, උදාහරණයක් ලෙස මෙම ප්‍රකාශය:

Object *myObject = new Object;

ඊට වඩා:

Object myObject;

නැතහොත් ශ්‍රිතයක් භාවිතා කරනවා වෙනුවට, අපි මෙසේ කියමු testFunc():

myObject.testFunc();

අපි ලිවිය යුතුයි:

myObject->testFunc();

නමුත් මට හිතාගන්න බැහැ ඇයි අපි මේ විදියට කරන්නෙ කියලා. මතක ලිපිනයට අපට access ජු ප්‍රවේශයක් ලැබෙන බැවින් එය කාර්යක්ෂමතාව හා වේගය සමඟ කළ යුතු යැයි මම සිතමි. මම හරිද?


409
මෙම ක්‍රියාව අනුගමනය කරනවාට වඩා ප්‍රශ්න කිරීම සඳහා ඔබට ප්‍රශංසාව. බොහෝ විට, දර්ශකයන් අධික ලෙස භාවිතා වේ.
ලුචියන් ග්‍රිගෝර්

121
දර්ශක භාවිතා කිරීමට හේතුවක් ඔබට නොපෙනේ නම්, එසේ නොකරන්න. වස්තූන් කැමති. අමු දර්ශකයන්ට පෙර shared_ptr ට පෙර unique_ptr ට පෙර වස්තු මනාප කරන්න.
ස්ටෙෆාන්

114
සටහන: ජාවා හි සෑම දෙයක්ම (මූලික වර්ග හැර) දර්ශකයකි. එබැවින් ඔබ ප්‍රතිවිරුද්ධ දේ විමසිය යුතුය: මට සරල වස්තු අවශ්‍ය වන්නේ ඇයි?
කරෝලි හෝර්වාත්

120
ජාවා හි, සින්ටැක්ස් මඟින් දර්ශකයන් සඟවා ඇති බව සලකන්න. C ++ හි, දර්ශකයක් සහ දර්ශකයක් නොවන අතර වෙනස කේතයෙන් පැහැදිලිව දක්වා ඇත. ජාවා සෑම තැනකම දර්ශක භාවිතා කරයි.
ඩැනියෙල් මාටින්

218
ලෙස සමීප ද පුළුල් ? ඇත්තටම? කරුණාකර ජනතාව, මෙම ජාවා ++ ක්‍රමලේඛන ක්‍රමය ඉතා සුලභ වන අතර C ++ ප්‍රජාවේ වැදගත්ම ගැටළුවකි . එය බරපතල ලෙස සැලකිය යුතුය.
මනු 343726

Answers:


1586

ඔබ බොහෝ විට ගතික ප්‍රතිපාදන දැකීම ඉතා අවාසනාවකි. එයින් පෙන්නුම් කරන්නේ නරක C ++ ක්‍රමලේඛකයින් කොපමණ සංඛ්‍යාවක් සිටිනවාද යන්නයි.

එක් අතකින්, ඔබට ප්‍රශ්න දෙකක් එකකට එකතු කර ඇත. පළමුවැන්න නම් අපි ගතික වෙන් කිරීම භාවිතා කළ යුත්තේ කවදාද යන්නයිnew ) යුත්තේ කවදාද? දෙවැන්න නම් අපි දර්ශකයන් භාවිතා කළ යුත්තේ කවදාද?

ගෙදර ගෙන යාමේ වැදගත් පණිවිඩය නම් ඔබ සැමවිටම කාර්යය සඳහා සුදුසු මෙවලම භාවිතා කළ යුතු බවයි බවයි. සෑම අවස්ථාවකම පාහේ, අතින් ගතික වෙන් කිරීම සහ / හෝ අමු දර්ශක භාවිතා කිරීමට වඩා සුදුසු සහ ආරක්ෂිත යමක් තිබේ.

ගතික වෙන් කිරීම

ඔබේ ප්‍රශ්නයේදී, ඔබ වස්තුවක් නිර්මාණය කිරීමේ ක්‍රම දෙකක් නිරූපණය කර ඇත. ප්රධාන වෙනස වන්නේ වස්තුවේ ගබඩා කාලයයි. කරන්නේ විට Object myObject;වාරණ තුළ, වස්තුව එය විෂය පථය පිටතට යන විට එය ස්වයංක්රීයව විනාශ වනු ඇත, ඉන් අදහස් ස්වයංක්රීය ගබඩා කාල සීමාව, නිර්මාණය කර ඇත. ඔබ එසේ කරන විට new Object(), වස්තුවට ගතික ගබඩා කාල සීමාවක් ඇත, එයින් අදහස් වන්නේ ඔබ deleteඑය පැහැදිලිව පවසන තුරු එය ජීවමානව පවතින බවයි. ඔබ භාවිතා කළ යුත්තේ ගතික ගබඩා කාලය ඔබට අවශ්‍ය වූ විට පමණි. එනම්, ඔබට හැකි සෑම විටම ස්වයංක්‍රීය ගබඩා කාල සීමාවක් සහිත වස්තු නිර්මාණය කිරීමට ඔබ කැමති විය යුතුය .

ඔබට ගතික වෙන් කිරීමක් අවශ්‍ය විය හැකි ප්‍රධාන අවස්ථා දෙක:

  1. වත්මන් විෂය පථය ඉක්මවා යාමට ඔබට වස්තුව අවශ්‍යයි - එම නිශ්චිත මතක ස්ථානයේ ඇති නිශ්චිත වස්තුව මිස එහි පිටපතක් නොවේ. වස්තුව පිටපත් කිරීම / ගෙනයාම ඔබ හරි නම් (බොහෝ විට ඔබ විය යුත්තේ), ඔබ කැමති ස්වයංක්‍රීය වස්තුවකට ය.
  2. ඔබට විශාල මතකයක් වෙන් කිරීමට අවශ්‍ය වන අතර එමඟින් තොගය පහසුවෙන් පිරවිය හැකිය. අපට මේ ගැන සැලකිලිමත් වීමට අවශ්‍ය නොවන්නේ නම් හොඳයි (බොහෝ විට ඔබට එසේ නොවිය යුතුය), එය ඇත්ත වශයෙන්ම C ++ විෂය පථයට පිටින් ඇති නමුත් අවාසනාවකට මෙන්, අපට පද්ධතිවල යථාර්ථය සමඟ කටයුතු කිරීමට සිදුවේ. අපි දියුණු වෙනවා.

ඔබට නියත වශයෙන්ම ගතික වෙන් කිරීමක් අවශ්‍ය වූ විට, ඔබ එය ස්මාර්ට් පොයින්ටරයකින් හෝ RAII (සම්මත බහාලුම් වැනි) සිදු කරන වෙනත් වර්ගයක සංයුක්ත කළ යුතුය. ස්මාර්ට් පොයින්ටර්ස් ගතිකව වෙන් කරන ලද වස්තූන්ගේ හිමිකාරිත්වය අර්ථ නිරූපණය කරයි. දෙස බලන්න std::unique_ptrසහ std::shared_ptr, නිදසුනක්. ඔබ ඒවා නිසි ලෙස භාවිතා කරන්නේ නම්, ඔබට ඔබේම මතක කළමනාකරණය කිරීම සම්පූර්ණයෙන්ම පාහේ වළක්වා ගත හැකිය ( ශුන්‍ය රීතිය බලන්න ).

පොයින්ටර්ස්

කෙසේ වෙතත්, ගතික වෙන්කිරීම් වලින් ඔබ්බට අමු දර්ශකයන් සඳහා තවත් පොදු භාවිතයන් ඇත, නමුත් බොහෝ ඒවාට ඔබ කැමති විකල්ප ඇත. පෙර මෙන්, ඔබට සැබවින්ම දර්ශකයන් අවශ්‍ය නම් මිස විකල්පයන්ට වැඩි කැමැත්තක් දක්වන්න .

  1. ඔබට යොමු අර්ථකථන අවශ්‍යයි . සමහර විට ඔබට වස්තුවක් දර්ශකයක් භාවිතයෙන් සම්මත කිරීමට අවශ්‍යය (එය වෙන් කළ ආකාරය නොසලකා) ඔබ එය පසුකර යන ශ්‍රිතයට එම නිශ්චිත වස්තුවට (එහි පිටපතක් නොව) ප්‍රවේශ වීමට අවශ්‍ය නිසා. කෙසේ වෙතත්, බොහෝ අවස්ථාවන්හීදී, ඔබ යොමු කරන්නන්ට යොමු වර්ග වලට වැඩි කැමැත්තක් දැක්විය යුතුය, මන්ද මෙය විශේෂයෙන් ඔවුන් නිර්මාණය කර ඇත්තේ එයයි. මෙය ඉහත 1 වැනි තත්වයේ දී මෙන් වත්මන් විෂය පථයෙන් ඔබ්බට වස්තුවේ ආයු කාලය දීර් about කිරීම නොවේ. පෙර මෙන්, වස්තුවක පිටපතක් යැවීමෙන් ඔබ හොඳ නම්, ඔබට යොමු අර්ථකථන අවශ්‍ය නොවේ.

  2. ඔබට බහුමාපකය අවශ්‍යයි . ඔබට ශ්‍රිත බහුඅවයවික ලෙස හැඳින්විය හැකිය (එනම්, වස්තුවක ගතික වර්ගය අනුව) දර්ශකයක් හෝ වස්තුවක් යොමු කිරීම හරහා පමණි. ඔබට අවශ්‍ය හැසිරීම එය නම්, ඔබට දර්ශකයන් හෝ යොමු කිරීම් භාවිතා කළ යුතුය. නැවතත්, යොමු කිරීම් වලට වැඩි කැමැත්තක් දැක්විය යුතුය.

  3. nullptrවස්තුව අතහැර දැමූ විට සම්මත කිරීමට ඉඩ දීමෙන් වස්තුවක් විකල්පයක් බව නිරූපණය කිරීමට ඔබට අවශ්‍යය . එය තර්කයක් නම්, පෙරනිමි තර්ක හෝ ක්‍රියාකාරී අධි බර භාවිතා කිරීමට ඔබ කැමති විය යුතුය. එසේ නොමැතිනම්, std::optional(C ++ 17 හි හඳුන්වා දී ඇත - පෙර C ++ ප්‍රමිතීන් සමඟ, භාවිතා කිරීම වැනි boost::optional) මෙම හැසිරීම සංවර්‍ධනය කරන වර්ගයක් භාවිතා කිරීම වඩාත් සුදුසුය .

  4. සම්පාදන කාලය වැඩි දියුණු කිරීම සඳහා ඔබට සම්පාදක ඒකක විසන්ධි කිරීමට අවශ්‍යය . දර්ශකයක ඇති ප්‍රයෝජනවත් ගුණාංගය නම්, ඔබට අවශ්‍ය වන්නේ යොමු කළ වර්ගයේ ඉදිරි ප්‍රකාශයක් පමණි (ඇත්ත වශයෙන්ම වස්තුව භාවිතා කිරීමට, ඔබට අර්ථ දැක්වීමක් අවශ්‍ය වේ). මෙය ඔබේ සම්පාදන ක්‍රියාවලියේ කොටස් විකේතනය කිරීමට ඉඩ සලසයි, එමඟින් සම්පාදන කාලය සැලකිය යුතු ලෙස වැඩි දියුණු කළ හැකිය. Pimpl idiom බලන්න .

  5. ඔබට සී පුස්තකාලයක් හෝ සී විලාසිතාවේ පුස්තකාලයක් සමඟ අතුරු මුහුණතක් අවශ්‍ය වේ . මෙම අවස්ථාවෙහිදී, ඔබට අමු දර්ශක භාවිතා කිරීමට බල කෙරෙයි. ඔබට කළ හැකි හොඳම දෙය නම්, ඔබේ අමු දර්ශකයන්ට අවසන් මොහොතේදී පමණක් ලිහිල් කිරීමට ඉඩ දීමයි. ඔබට ස්මාර්ට් පොයින්ටරයකින් අමු දර්ශකයක් ලබා ගත හැකිය, නිදසුනක් ලෙස, එහි getසාමාජික ක්‍රියාකාරිත්වය භාවිතා කිරීමෙන් . පුස්තකාලයක් ඔබ වෙනුවෙන් යම්කිසි ප්‍රතිපාදනයක් සිදු කරන්නේ නම්, එය හසුරුව හරහා ගනුදෙනු කිරීමට අපේක්ෂා කරයි නම්, ඔබට බොහෝ විට හසුරුව ස්මාර්ට් පොයින්ටරයකින් අභිරුචි මකාදැමීමකින් ඔතා එවිය හැකිය.


84
"වත්මන් විෂය පථය ඉක්මවා යාමට ඔබට වස්තුව අවශ්‍යයි." - මේ පිළිබඳ අමතර සටහනක්: වත්මන් විෂය පථය ඉක්මවා යාමට ඔබට වස්තුව අවශ්‍ය යැයි පෙනෙන අවස්ථා තිබේ, නමුත් ඔබ එසේ නොකරයි. ඔබ ඔබේ වස්තුව දෛශිකයක් තුළට දැමුවහොත්, උදාහරණයක් ලෙස, වස්තුව දෛශිකයට පිටපත් කරනු ලැබේ (හෝ ගෙන යනු ලැබේ), සහ මුල් වස්තුව එහි විෂය පථය අවසන් වූ විට විනාශ කිරීමට ආරක්ෂිත වේ.

25
දැන් බොහෝ ස්ථානවල s / copy / move / බව මතක තබා ගන්න. වස්තුවක් ආපසු ලබා දීම නිසැකවම චලනය කිරීමක් අදහස් නොකරයි. වස්තුවක් දර්ශකයක් හරහා ප්‍රවේශ වීම විකලාංග වන අතර එය නිර්මාණය වූ ආකාරය ද සැලකිල්ලට ගත යුතුය.
බලු පැටියා

15
මෙම පිළිතුර පිළිබඳ RAII පිළිබඳ පැහැදිලි සඳහනක් මට මග හැරී ඇත. C ++ යනු සම්පත් කළමනාකරණය පිළිබඳ සියල්ලම (සියල්ලම පාහේ) වන අතර RAII යනු C ++ මත එය කළ හැකි ක්‍රමයයි (සහ අමු දර්ශකයන් ජනනය කරන ප්‍රධාන ගැටළුව: RAII බිඳීම)
Manu343726

11
C ++ 11 ට පෙර ස්මාර්ට් පොයින්ටර්ස් පැවතුනි, උදා: boost :: shared_ptr සහ boost :: scoped_ptr. වෙනත් ව්‍යාපෘති වලට තමන්ගේම සමානත්වයක් ඇත. ඔබට චලනය වන අර්ථකථන ලබා ගත නොහැකි අතර, std :: auto_ptr හි පැවරුම දෝෂ සහිතය, එබැවින් C ++ 11 දේවල් වැඩි දියුණු කරයි, නමුත් උපදෙස් තවමත් හොඳයි. (එවිට දුක් nitpick, ඒ සඳහා ප්රවේශයන් ප්රමාණවත් නොවේ එය C ++ 11 සිදුවීමටත්, එය අවශ්ය සියලු අවස්තා ඔබ සමහරවිට සහාය C ++ 11 සමග වැඩ කිරීමට ඔබගේ කේතය ඔබට අවශ්ය විය හැකිය බව ය. ඔව්, ඔරකල් Solaris ශබ්දාගාර, මම ඉන්නේ ඔබ දෙස බලයි.)
armb

7
@ MDMoore313 ඔබට ලිවිය හැකියObject myObject(param1, etc...)
user000001

174

දර්ශකයන් සඳහා බොහෝ භාවිත අවස්ථා තිබේ.

බහුමාමක හැසිරීම . බහුමාමක වර්ග සඳහා, කැපීම වළක්වා ගැනීම සඳහා දර්ශක (හෝ යොමු) භාවිතා කරයි:

class Base { ... };
class Derived : public Base { ... };

void fun(Base b) { ... }
void gun(Base* b) { ... }
void hun(Base& b) { ... }

Derived d;
fun(d);    // oops, all Derived parts silently "sliced" off
gun(&d);   // OK, a Derived object IS-A Base object
hun(d);    // also OK, reference also doesn't slice

අර්ථ නිරූපණය සහ පිටපත් කිරීමෙන් වළකින්න . බහු අවයවික නොවන වර්ග සඳහා, දර්ශකයක් (හෝ යොමු කිරීමක්) මිල අධික විය හැකි වස්තුවක් පිටපත් කිරීමෙන් වළක්වනු ඇත

Base b;
fun(b);  // copies b, potentially expensive 
gun(&b); // takes a pointer to b, no copying
hun(b);  // regular syntax, behaves as a pointer

C ++ 11 හි චලනය වන අර්ථකථන ඇති අතර එමඟින් මිල අධික වස්තූන්ගේ පිටපත් බොහෝමයක් ක්‍රියාකාරී තර්කයට සහ ප්‍රතිලාභ අගයන් ලෙස වළක්වා ගත හැකිය. නමුත් දර්ශකයක් භාවිතා කිරීමෙන් නියත වශයෙන්ම ඒවා වළක්වා ගත හැකි අතර එකම වස්තුවක් මත බහුවිධ දර්ශකයන්ට ඉඩ දෙනු ඇත (වස්තුවක් ගෙන යා හැක්කේ එක් වරක් පමණි).

සම්පත් අත්පත් කර ගැනීම . newක්‍රියාකරු භාවිතා කරමින් සම්පතකට දර්ශකයක් නිර්මාණය කිරීම නූතන C ++ හි ප්‍රති-රටාවකි . විශේෂ සම්පත් පන්තියක් (සම්මත බහාලුම් වලින් එකක්) හෝ ස්මාර්ට් පොයින්ටරයක් ( std::unique_ptr<>හෝ std::shared_ptr<>) භාවිතා කරන්න. සලකා බලන්න:

{
    auto b = new Base;
    ...       // oops, if an exception is thrown, destructor not called!
    delete b;
}

එදිරිව.

{
    auto b = std::make_unique<Base>();
    ...       // OK, now exception safe
}

අමු දර්ශකයක් භාවිතා කළ යුත්තේ “දර්ශනයක්” ලෙස මිස කිසිදු ආකාරයකින් හිමිකාරිත්වයට සම්බන්ධ නොවිය යුතුය, එය සෘජු නිර්මාණය හරහා හෝ ව්‍යංගයෙන් ප්‍රතිලාභ අගයන් හරහා වේවා. C ++ නිති අසන ප්‍රශ්න වලින් මෙම ප්‍රශ්නාවලිය බලන්න .

තවත් සියුම් ජීවිත කාලය පාලනය කරන සෑම අවස්ථාවකදීම (උදා: උත්සවයකට තර්කයක් ලෙස) හවුල් පහිටුම් දක්වනය පිටපත් කොට ඇත එය පෙන්නුම් සම්පත් ජීවත් තබා ඇත. newවිෂය පථයෙන් පිටතට යන විට නිත්‍ය වස්තූන් (ඔබ විසින් සෘජුවම හෝ සම්පත් පන්තියක් තුළ නිර්මාණය කර නැත) විනාශ වේ.


17
"නව ක්‍රියාකරු භාවිතා කරමින් සම්පතකට දර්ශකයක් නිර්මාණය කිරීම ප්‍රති-රටාවකි" අමු දර්ශකයක් තමන් සතු කර ගැනීම ප්‍රති-රටාවක් බව ඔබට වැඩි දියුණු කළ හැකි යැයි මම සිතමි . නිර්මාණය කිරීම පමණක් නොව, හිමිකාරිත්වය පැවරීම ඇඟවුම් කරන අමු දර්ශක තර්ක හෝ ප්‍රතිලාභ අගයන් ලෙස සම්මත කිරීම IMHO unique_ptr/ අර්ථකථන වලින් ඉවත් කරනු ලැබේ
dyp

1
ddyp tnx, යාවත්කාලීන කර මෙම මාතෘකාව පිළිබඳ C ++ නිති අසන ප්‍රශ්න හා පිළිතුරු වෙත යොමු කරන්න.
TemplateRex

4
සෑම තැනකම ස්මාර්ට් පොයින්ටර් භාවිතා කිරීම ප්‍රති-රටාවකි. එය අදාළ වන විශේෂ අවස්ථා කිහිපයක් තිබේ, නමුත් බොහෝ විට, ගතික වෙන් කිරීම (අත්තනෝමතික ජීවිත කාලය) සඳහා තර්ක කරන එකම හේතුව සුපුරුදු ස්මාර්ට් පොයින්ටර්ස් වලට එරෙහිව තර්ක කරයි.
ජේම්ස් කන්සේ

2
Ames ජේම්ස් කන්ස් ස්මාර්ට් පොයින්ටර්ස් සෑම තැනකම භාවිතා කළ යුතු බව ඇඟවීමට මම අදහස් නොකළෙමි, එය හිමිකාරිත්වය සඳහා පමණක් නොව, අමු දර්ශක හිමිකාරිත්වය සඳහා නොව අදහස් සඳහා පමණක් භාවිතා කළ යුතුය.
TemplateRex

2
EmTemplateRex එය තරමක් මෝඩකමක් ලෙස පෙනේ, එය hun(b)සම්පාදනය වන තෙක් ඔබ වැරදි වර්ගය සැපයූ බව නොදැන ඔබ හොඳින් නම් මිස අත්සන පිළිබඳ දැනුමක් අවශ්‍ය වේ. විමර්ශන ගැටළුව සාමාන්‍යයෙන් සම්පාදනය කරන වේලාවට හසු නොවනු ඇති අතර නිදොස් කිරීමට වැඩි උත්සාහයක් ගනු ඇත, ඔබ තර්ක නිවැරදිදැයි තහවුරු කර ගැනීම සඳහා අත්සන පරීක්ෂා කරන්නේ නම් ඔබට ඕනෑම තර්කයක් යොමු දැයි බැලීමටද හැකි වේ. එබැවින් යොමු බිට් ගැටළුවක් නොවන දෙයක් බවට පත්වේ (විශේෂයෙන් තෝරාගත් ශ්‍රිතයක අත්සන පෙන්වන IDEs හෝ පෙළ සංස්කාරක භාවිතා කරන විට). එසේම , const&.
JAB

132

ඉදිරි ප්‍රකාශ, බහුමාපකය වැනි වැදගත් භාවිත අවස්ථා ඇතුළුව මෙම ප්‍රශ්නයට විශිෂ්ට පිළිතුරු රාශියක් ඇත, නමුත් ඔබේ ප්‍රශ්නයේ “ආත්මයේ” කොටසක් පිළිතුරු නොලැබෙන බව මට හැඟේ - එනම් ජාවා සහ සී ++ හරහා විවිධ වාක්‍ය ඛණ්ඩයන් අදහස් කරන්නේ කුමක්ද.

භාෂා දෙක සංසන්දනය කිරීමේදී තත්වය විමසා බලමු:

ජාවා:

Object object1 = new Object(); //A new object is allocated by Java
Object object2 = new Object(); //Another new object is allocated by Java

object1 = object2; 
//object1 now points to the object originally allocated for object2
//The object originally allocated for object1 is now "dead" - nothing points to it, so it
//will be reclaimed by the Garbage Collector.
//If either object1 or object2 is changed, the change will be reflected to the other

මෙයට ආසන්නතම සමාන වන්නේ:

සී ++:

Object * object1 = new Object(); //A new object is allocated on the heap
Object * object2 = new Object(); //Another new object is allocated on the heap
delete object1;
//Since C++ does not have a garbage collector, if we don't do that, the next line would 
//cause a "memory leak", i.e. a piece of claimed memory that the app cannot use 
//and that we have no way to reclaim...

object1 = object2; //Same as Java, object1 points to object2.

විකල්ප C ++ මාර්ගය බලමු:

Object object1; //A new object is allocated on the STACK
Object object2; //Another new object is allocated on the STACK
object1 = object2;//!!!! This is different! The CONTENTS of object2 are COPIED onto object1,
//using the "copy assignment operator", the definition of operator =.
//But, the two objects are still different. Change one, the other remains unchanged.
//Also, the objects get automatically destroyed once the function returns...

එය සිතිය හැකි හොඳම ක්‍රමය නම් - වැඩි හෝ අඩු - ජාවා (ව්‍යංගයෙන්) වස්තූන් සඳහා දර්ශකයන් හසුරුවන අතර C ++ මඟින් වස්තූන් වෙත හෝ වස්තූන් විසින්ම දර්ශකයන් හසුරුවනු ඇත. මේ සඳහා ව්‍යතිරේකයන් ඇත - නිදසුනක් ලෙස, ඔබ ජාවා "ප්‍රාථමික" වර්ග ප්‍රකාශ කරන්නේ නම්, ඒවා සත්‍ය වශයෙන්ම පිටපත් කර ඇති අගයන් මිස දර්ශකයන් නොවේ. නිසා,

ජාවා:

int object1; //An integer is allocated on the stack.
int object2; //Another integer is allocated on the stack.
object1 = object2; //The value of object2 is copied to object1.

එයින් කියැවෙන්නේ, කරුණු භාවිතා කිරීම නිවැරදි හෝ වැරදි ක්‍රමයක් නොවන බවයි. කෙසේ වෙතත් වෙනත් පිළිතුරු එය සතුටුදායක ලෙස ආවරණය කර ඇත. සාමාන්‍ය අදහස නම්, C ++ තුළ ඔබට වස්තූන්ගේ ජීවිත කාලය සහ ඒවා ජීවත්වන ස්ථානය මත වැඩි පාලනයක් ඇති බවයි.

නිවෙස් ලක්ෂ්‍යය ගන්න - Object * object = new Object()ඉදිකිරීම් යනු සැබවින්ම සාමාන්‍ය ජාවා (හෝ ඒ සඳහා C #) අර්ථ නිරූපණයට ආසන්නතම දෙයයි.


7
Object2 is now "dead": මම හිතන්නේ ඔබ අදහස් කළේ myObject1හෝ වඩාත් නිවැරදිව the object pointed to by myObject1.
ක්ලෙමන්ට්

2
ඇත්ත වශයෙන්ම! ටිකක් නැවත මුද්‍රණය කළා.
ජෙරසිමෝස් ආර්

2
Object object1 = new Object(); Object object2 = new Object();ඉතා නරක කේතයකි. දෙවන නව හෝ දෙවන වස්තු සාදන්නා විසි කළ හැකි අතර දැන් වස්තුව 1 කාන්දු වී ඇත. ඔබ අමු news භාවිතා කරන්නේ නම් , ඔබ newASAP හි RAII එතීම්වල එඩ් වස්තු ඔතා තිබිය යුතුය .
පීඑස්කොසික්

8
ඇත්ත වශයෙන්ම, මෙය වැඩසටහනක් නම්, ඒ වටා වෙන කිසිවක් සිදු නොවේ. ස්තුතිවන්ත විය යුතු කරුණක් නම්, මෙය සී ++ හි දර්ශකයක් හැසිරෙන ආකාරය පෙන්වන පැහැදිලි කිරීමක් පමණි - සහ RAII වස්තුවක් අමු දර්ශකයක් සඳහා ආදේශ කළ නොහැකි ස්ථාන කිහිපයෙන් එකක්, අමු දර්ශක ගැන අධ්‍යයනය කරමින් ඉගෙන ගනිමින් සිටී ...
ජෙරසිමෝස් ආර්

80

දර්ශක භාවිතා කිරීමට තවත් හොඳ හේතුවක් වනුයේ ඉදිරි ප්‍රකාශ සඳහා ය . ප්‍රමාණවත් තරම් විශාල ව්‍යාපෘතියක දී ඔවුන්ට සැබවින්ම කාලය සම්පාදනය කළ හැකිය.


7
මෙය සැබවින්ම ප්‍රයෝජනවත් තොරතුරු සම්මිශ්‍රණයට එකතු කිරීමකි, එබැවින් ඔබ එයට පිළිතුරක් ලබා දීම ගැන සතුටුයි!
TemplateRex

3
std :: shared_ptr <T> ටී හි ඉදිරි ප්‍රකාශ සමඟද ක්‍රියා කරයි. (std :: unique_ptr <T> නැත )
බර්කස්

13
ඇබර්කස්: std::unique_ptr<T>ඉදිරි ප්‍රකාශ සමඟ ක්‍රියා Tකරයි. විනාශ කරන්නා std::unique_ptr<T>හැඳින්වූ විට Tඑය සම්පූර්ණ වර්ගයක් බව ඔබ සහතික කර ගත යුතුය. මෙයින් සාමාන්‍යයෙන් අදහස් කරන්නේ std::unique_ptr<T>ශීර්ෂ ගොනුවේ එහි විනාශකරුවා ප්‍රකාශයට පත් කරන ඔබේ පන්තිය සහ එය සීපීපී ගොනුවේ ක්‍රියාත්මක කිරීමයි (ක්‍රියාත්මක කිරීම හිස් වුවද).
ඩේවිඩ් ස්ටෝන්

මොඩියුලයන් මෙය නිවැරදි කරයිද?
ට්‍රෙවර් හිකී

ReTrevorHickey පැරණි අදහස් මම දනිමි, නමුත් කෙසේ හෝ එයට පිළිතුරු දීමට. මොඩියුලයන් යැපීම ඉවත් නොකරනු ඇත, නමුත් යැපීම ඇතුළුව ඉතා ලාභදායී විය යුතුය, කාර්ය සාධන පිරිවැය අනුව පාහේ නොමිලේ. එසේම, ඔබේ සම්පාදක වේලාවන් පිළිගත හැකි පරාසයකට ගෙන ඒමට මොඩියුල වලින් සාමාන්‍ය වේගවත් කිරීම ප්‍රමාණවත් නම්, එය තවදුරටත් ගැටළුවක් නොවේ.
අයිඩියාකාපි

80

පෙරවදන

ජාවා යනු සී ++ වැනි කිසිවක් නොවේ. ජාවා හයිප් යන්ත්‍රය ඔබ විශ්වාස කිරීමට කැමතියි ජාවා සින්ටැක්ස් වැනි C ++ ඇති බැවින් භාෂා සමාන බව. සත්‍යයෙන් තවත් කිසිවක් කළ නොහැකිය. මෙම වැරදි තොරතුරු ජාවා ක්‍රමලේඛකයින් C ++ වෙත ගොස් ඔවුන්ගේ කේතයේ ඇඟවුම් තේරුම් නොගෙන ජාවා වැනි සින්ටැක්ස් භාවිතා කිරීමට හේතුවකි.

ඉදිරියට අපි යමු

නමුත් මට හිතාගන්න බැහැ ඇයි අපි මේ විදියට කරන්නෙ කියලා. මතක ලිපිනයට අපට access ජු ප්‍රවේශයක් ලැබෙන බැවින් එය කාර්යක්ෂමතාව හා වේගය සමඟ කළ යුතු යැයි මම සිතමි. මම හරිද?

ඊට පටහැනිව, ඇත්ත වශයෙන්ම. ගොඩවල් ගොඩට වඩා මන්දගාමී ය, මන්ද යත් ගොඩට සාපේක්ෂව තොගය ඉතා සරල ය. ස්වයංක්‍රීය ගබඩා විචල්‍යයන් (aka stack variable) ඒවායේ විෂය පථයෙන් බැහැර වූ පසු ඒවායේ විනාශ කරන්නන් කැඳවනු ලැබේ. උදාහරණයක් වශයෙන්:

{
    std::string s;
}
// s is destroyed here

අනෙක් අතට, ඔබ ගතිකව වෙන් කර ඇති දර්ශකයක් භාවිතා කරන්නේ නම්, එහි විනාශ කරන්නා අතින් කැඳවිය යුතුය. deleteඔබ වෙනුවෙන් මෙම විනාශ කරන්නා අමතන්න.

{
    std::string* s = new std::string;
}
delete s; // destructor called

newසී # සහ ජාවා වල පවතින සින්ටැක්ස් සමඟ මෙයට කිසිදු සම්බන්ධයක් නැත . ඒවා සම්පූර්ණයෙන්ම වෙනස් අරමුණු සඳහා යොදා ගනී.

ගතික වෙන්කිරීමේ ප්‍රතිලාභ

1. අරාවෙහි ප්‍රමාණය ඔබ කල්තියා දැනගත යුතු නැත

බොහෝ සී ++ ක්‍රමලේඛකයින් මුහුණ දෙන පළමු ගැටලුව නම්, ඔවුන් පරිශීලකයින්ගෙන් අත්තනෝමතික ආදානය භාර ගන්නා විට, ඔබට වෙන් කළ හැක්කේ ස්ථාවර විචල්‍යයක් සඳහා ස්ථාවර ප්‍රමාණයක් පමණි. ඔබට අරා වල ප්‍රමාණයද වෙනස් කළ නොහැක. උදාහරණයක් වශයෙන්:

char buffer[100];
std::cin >> buffer;
// bad input = buffer overflow

ඇත්ත වශයෙන්ම, ඔබ std::stringඒ වෙනුවට භාවිතා කළේ නම්, std::stringගැටලුවක් නොවිය යුතු අභ්‍යන්තරව ප්‍රමාණය වෙනස් වේ. නමුත් මූලික වශයෙන් මෙම ගැටලුවට විසඳුම ගතික වෙන් කිරීමකි. පරිශීලකයාගේ ආදානය මත පදනම්ව ඔබට ගතික මතකය වෙන් කළ හැකිය, උදාහරණයක් ලෙස:

int * pointer;
std::cout << "How many items do you need?";
std::cin >> n;
pointer = new int[n];

පැති සටහන : බොහෝ ආරම්භකයින් කරන එක් අත්වැරැද්දක් වන්නේ විචල්ය දිග අරා භාවිතා කිරීමයි. මෙය GNU දිගුවක් වන අතර එය ක්ලැන්ග්හි එකක් වන අතර ඒවා GCC හි බොහෝ දිගු පිළිබිඹු කරයි. එබැවින් පහත සඳහන් දෑ int arr[n]මත රඳා නොසිටිය යුතුය.

ගොඩවල් තොගයට වඩා විශාල බැවින් කෙනෙකුට අත්තනෝමතික ලෙස ඔහුට / ඇයට අවශ්‍ය තරම් මතකය වෙන් කළ හැකිය / නැවත වෙන් කළ හැකිය, එහෙත් තොගයට සීමාවක් ඇත.

2. අරා දර්ශකයන් නොවේ

මෙය ඔබ ඉල්ලන ප්‍රතිලාභයක් වන්නේ කෙසේද? අරා සහ පොයින්ටර් පිටුපස ඇති ව්‍යාකූලත්වය / මිථ්‍යාව තේරුම් ගත් පසු පිළිතුර පැහැදිලි වනු ඇත. ඒවා එක හා සමාන යැයි පොදුවේ උපකල්පනය කෙරේ, නමුත් ඒවා එසේ නොවේ. මෙම මිථ්‍යාව පැමිණෙන්නේ දර්ශකයන් අරා මෙන් දායක විය හැකි නිසා සහ ශ්‍රිත ප්‍රකාශනයක ඉහළ මට්ටමේ දර්ශකයන්ට අරා ක්ෂය වීම නිසා ය. කෙසේ වෙතත්, අරාව දර්ශකයකට ක්ෂය වූ පසු, දර්ශකයට එහි sizeofතොරතුරු නැති වේ . ඒ නිසා sizeof(pointer)සාමාන්යයෙන් 64-bit පද්ධති මත 8 බයිට් වන, බයිට් වලින් පෙන්නුම් කරන්නක් ප්රමාණය ලබා දෙනු ඇත.

ඔබට අරා වලට පැවරිය නොහැක, ඒවා ආරම්භ කිරීම පමණි. උදාහරණයක් වශයෙන්:

int arr[5] = {1, 2, 3, 4, 5}; // initialization 
int arr[] = {1, 2, 3, 4, 5}; // The standard dictates that the size of the array
                             // be given by the amount of members in the initializer  
arr = { 1, 2, 3, 4, 5 }; // ERROR

අනෙක් අතට, ඔබට අවශ්‍ය ඕනෑම දෙයක් දර්ශකයන් සමඟ කළ හැකිය. අවාසනාවකට මෙන්, දර්ශක සහ අරා අතර වෙනස ජාවා සහ සී # හි අතින් රැළි ඇති හෙයින්, ආරම්භකයින්ට වෙනස තේරෙන්නේ නැත.

3. බහුමාපකය

ජාවා සහ සී # ඔබට වෙනත් වස්තුවක් ලෙස සැලකීමට ඉඩ සලසන පහසුකම් ඇත, උදාහරණයක් ලෙස asමූල පදය භාවිතා කිරීම . එබැවින් යමෙකුට යම් Entityවස්තුවක් වස්තුවක් ලෙස සැලකීමට අවශ්‍ය නම් Player, කෙනෙකුට එය කළ හැක්කේ Player player = Entity as Player;ඔබ සමජාතීය බහාලුමක් මත ශ්‍රිත ඇමතීමට අදහස් කරන්නේ නම් එය විශේෂිත වර්ගයකට පමණක් අදාළ විය යුතුය. පහත දැක්වෙන සමාන ආකාරයකින් ක්‍රියාකාරීත්වය ලබා ගත හැකිය:

std::vector<Base*> vector;
vector.push_back(&square);
vector.push_back(&triangle);
for (auto& e : vector)
{
     auto test = dynamic_cast<Triangle*>(e); // I only care about triangles
     if (!test) // not a triangle
        e.GenericFunction();
     else
        e.TriangleOnlyMagic();
}

එබැවින් කියන්න ත්‍රිකෝණවලට භ්‍රමණය වන ශ්‍රිතයක් තිබුනේ නම්, ඔබ එය පන්තියේ සියලුම වස්තු මත ඇමතීමට උත්සාහ කළහොත් එය සම්පාදක දෝෂයක් වනු ඇත. භාවිතා කිරීමෙන් dynamic_cast, ඔබට asමූලික පදය අනුකරණය කළ හැකිය . පැහැදිලිව කිවහොත්, වාත්තු කිරීම අසමත් වුවහොත් එය අවලංගු දර්ශකයක් ලබා දෙයි. එබැවින් NULL හෝ අවලංගු දර්ශකයක්ද යන්න !testපරීක්ෂා කිරීම සඳහා කෙටියෙන් දැක්විය යුතුය test, එයින් අදහස් වන්නේ වාත්තු කිරීම අසාර්ථක බවයි.

ස්වයංක්‍රීය විචල්යයන්ගේ ප්රතිලාභ

ගතික ප්‍රතිපාදන මගින් කළ හැකි සියලු ශ්‍රේෂ් things දේ දැකීමෙන් පසු, ඔබ සිතන්නේ කිසිවෙකු නිතරම ගතික ප්‍රතිපාදන භාවිතා නොකරන්නේ මන්ද යන්නයි. මම දැනටමත් ඔබට එක් හේතුවක් පවසා ඇත, ගොඩවල් මන්දගාමී වේ. ඔබට ඒ සියලු මතකය අවශ්‍ය නොවේ නම්, ඔබ එය අනිසි ලෙස භාවිතා නොකළ යුතුය. එබැවින් විශේෂිත අනුපිළිවෙලක අවාසි කිහිපයක් මෙහි දැක්වේ:

  • එය දෝෂ සහිත ය. අතින් මතකය වෙන් කිරීම භයානක වන අතර ඔබ කාන්දුවීම් වලට ගොදුරු වේ. නිදොස්කරණය හෝ valgrind(මතක කාන්දු වන මෙවලමක්) භාවිතා කිරීමට ඔබ ප්‍රවීණ නොවන්නේ නම් , ඔබේ හිසකෙස් ඔබේ හිසෙන් ඉවතට ගත හැකිය. වාසනාවකට මෙන් RAII මෝඩයන් සහ ස්මාර්ට් පොයින්ටර්ස් මෙය ටිකක් සමනය කරයි, නමුත් ඔබ තුනේ රීතිය සහ පහේ රීතිය වැනි භාවිතයන් ගැන දැන සිටිය යුතුය. එය ගත යුතු තොරතුරු රාශියක් වන අතර, නොදන්නා හෝ ගණන් නොගන්නා ආරම්භකයින් මෙම උගුලට වැටෙනු ඇත.

  • එය අවශ්‍ය නොවේ. ජාවා සහ සී # මෙන් නොව new, සෑම තැනකම යතුරුපදය භාවිතා කිරීම මුග්ධය, සී ++ හි, ඔබ එය භාවිතා කළ යුත්තේ ඔබට අවශ්‍ය නම් පමණි. පොදු වාක්‍ය ඛණ්ඩය යන්නේ, ඔබට මිටියක් තිබේ නම් සියල්ල නියපොතු මෙන් පෙනේ. C ++ සමඟ ආරම්භ කරන ආරම්භකයින් දර්ශකයන්ට බිය වන අතර පුරුද්දෙන් සිරස් විචල්‍යයන් භාවිතා කිරීමට ඉගෙන ගන්නා අතර, ජාවා සහ සී # ක්‍රමලේඛකයින් එය තේරුම් නොගෙන දර්ශක භාවිතා කිරීමෙන් ආරම්භ වේ ! එය වචනාර්ථයෙන් වැරදි පාදයෙන් ඉවත් වීමයි. සින්ටැක්ස් එක දෙයක් නිසා, භාෂාව ඉගෙනීම තවත් දෙයක් නිසා ඔබ දන්නා සියල්ල අතහැර දැමිය යුතුයි.

1. (N) RVO - අකා, (නම් කරන ලද) ප්‍රතිලාභ අගය ප්‍රශස්තකරණය

බොහෝ සම්පාදකයින් විසින් සිදුකරන එක් ප්‍රශස්තිකරණයක් වන්නේ එලිසන් සහ ප්‍රතිලාභ අගය ප්‍රශස්තිකරණය යනුවෙනි . බොහෝ මූලද්‍රව්‍ය අඩංගු දෛශිකයක් වැනි ඉතා විශාල වස්තූන් සඳහා ප්‍රයෝජනවත් වන අනවශ්‍ය පිටපත් මේ දේවල් මග හැරිය හැක. සාමාන්‍යයෙන් පොදු සිරිත වන්නේ අයිතිය පැවරීම සඳහා දර්ශක භාවිතා කිරීමයි විශාල වස්තූන් එහා මෙහා ගෙනයාම වෙනුවට පිටපත් කිරීම වෙනුවට කිරීමයි. මෙය චලනය අර්ථ නිරූපණයන් සහ ස්මාර්ට් පොයින්ටර්ස් ආරම්භ කිරීමට හේතු වී තිබේ .

ඔබ දර්ශක භාවිතා කරන්නේ නම්, (N) RVO සිදු නොවේ . ඔබ ප්‍රශස්තිකරණය ගැන කනස්සල්ලට පත්වුවහොත්, දර්ශකයන් ආපසු යැවීමට හෝ පසුකර යාමට වඩා (N) RVO හි වාසිය ලබා ගැනීම වඩා වාසිදායක සහ අඩු දෝෂ සහිත වේ. ශ්‍රිතයක ඇමතුම්කරු වගකිව යුතු නම් දෝෂ කාන්දුවීම් සිදුවිය හැකියdeleteගතිකව වෙන් කරන ලද වස්තුවක් . උණුසුම් අර්තාපල් මෙන් දර්ශකයන් වටා ගමන් කරන්නේ නම් වස්තුවක හිමිකාරිත්වය සොයා ගැනීම දුෂ්කර විය හැකිය. එය සරල හා වඩා හොඳ බැවින් ස්ටක් විචල්යයන් භාවිතා කරන්න.


"ඉතින්! පරීක්ෂණය අත්‍යවශ්‍යයෙන්ම පරීක්ෂණය NULL ද නැතිනම් අවලංගු දර්ශකයක් ද යන්න පරීක්ෂා කිරීම සඳහා වූ කෙටි යෙදුමකි. එයින් අදහස් වන්නේ වාත්තු කිරීම අසාර්ථක වූ බවයි." මෙම වාක්‍යය පැහැදිලි කිරීම සඳහා නැවත ලිවිය යුතු යැයි මම සිතමි.
බර්කස්

4
"ජාවා හයිප් යන්ත්රය ඔබ විශ්වාස කිරීමට කැමතියි" - සමහර විට 1997 දී විය හැකිය, නමුත් මෙය දැන් කාලානුරූපී ය, 2014 දී ජාවා සී ++ සමඟ සංසන්දනය කිරීමට තවදුරටත් පෙළඹවීමක් නොමැත.
මැට් ආර්

16
පැරණි ප්‍රශ්නය, නමුත් කේත කොටසේ { std::string* s = new std::string; } delete s; // destructor called.... නිසැකවම මෙය ක්‍රියා deleteනොකරන්නේ සම්පාදකයා තවදුරටත් කුමක් දැයි නොදන්නා නිසාද s?
badger5000

2
මම -1 ලබා දෙන්නේ නැත, නමුත් ආරම්භක ප්‍රකාශයන් ලියා ඇති පරිදි මම එකඟ නොවෙමි. පළමුවෙන්ම, කිසියම් "උපකල්පනයක්" ඇති බවට මම එකඟ නොවෙමි - Y2K වටා විය හැකිය, නමුත් දැන් භාෂා දෙකම හොඳින් වටහාගෙන ඇත. දෙවනුව, ඔවුන් තරමක් සමාන යැයි මම තර්ක කරමි - සී ++ යනු සිමියුලා සමඟ විවාහ වූ සීගේ දරුවා, ජාවා අතථ්‍ය යන්ත්‍රය එකතු කරයි, කසළ එකතු කරන්නා සහ හෙවිලි විශේෂාංග අඩු කරයි, සහ සී # ක්‍රමවත් කර නැති අතර ජාවා වෙත නැවත හඳුන්වා දෙයි. ඔව්, මෙය රටා සහ වලංගු භාවිතය විශාල වශයෙන් වෙනස් කරයි, නමුත් පොදු යටිතල පහසුකම් / අවතක්සේරු කිරීම වටහා ගැනීම ප්‍රයෝජනවත් වන අතර එමඟින් කෙනෙකුට වෙනස්කම් දැකගත හැකිය.
ජෙරසිමෝස් ආර්

1
Ames ජේම්ස් මැට්ටා: මතකය මතකය බව ඔබ ඇත්ත වශයෙන්ම නිවැරදියි, ඒවා දෙකම එකම භෞතික මතකයෙන් වෙන් කර ඇත, නමුත් සලකා බැලිය යුතු එක් කරුණක් නම්, වෙන් කර ඇති වස්තූන් සමඟ වැඩ කරන වඩා හොඳ කාර්ය සාධන ලක්ෂණ ලබා ගැනීම ඉතා සුලභ වීමයි. හෝ එහි ඉහල ම මට්ටමේ අවම වශයෙන් - ෙයාදා එසේ එවැනි ප්රතිලාභ නැහැ අතර ඔබ ගොඩක් පහිටුම් දක්වනය හඹා යාම නම් ඔබ, කාර්යයන් ඇතුලත් කරන්න සහ පිටවීමේ ලෙස පූර්වාපේක්ෂීව සංචිත කෙරී "උණුසුම්" වීම ඉතා ඉහළ අවස්ථාවක් තියෙනවා හැක කරන බහු හැඹිලි වදින්නේ නැහැ ලබා ඔබ බොහෝ විට තොගයේ නොසිටිනු ඇත. නමුත් මේ සියලු "අහඹු බව" සාමාන්‍යයෙන් තොගයට කැමති වේ.
ජෙරසිමෝස් ආර්

23

C ++ මඟින් ඔබට වස්තුවක් සම්මත කිරීමට ක්‍රම තුනක් ලබා දෙයි: දර්ශකය, යොමු කිරීම සහ අගය අනුව. ජාවා ඔබව දෙවැන්න සමඟ සීමා කරයි (එකම ව්‍යතිරේකය වන්නේ int, boolean යනාදිය වැනි ප්‍රාථමික වර්ග වේ). ඔබට අමුතු සෙල්ලම් බඩුවක් මෙන් නොව C ++ භාවිතා කිරීමට අවශ්‍ය නම්, මෙම ක්‍රම තුන අතර වෙනස ඔබ දැන ගැනීම හොඳය.

'මෙය විනාශ කළ යුත්තේ කවුරුන් සහ කවදාද?' වැනි ගැටලුවක් නොමැති බව ජාවා මවා පෙන්වයි. පිළිතුර: කසළ එකතු කරන්නා, ශ්‍රේෂ් and හා භයානක ය. එසේ වුවද, එයට මතක කාන්දුවීම් වලින් 100% ආරක්ෂාවක් සැපයිය නොහැක (ඔව්, ජාවා මගින් මතකය කාන්දු විය හැක ). ඇත්ත වශයෙන්ම, GC ඔබට ආරක්ෂාව පිළිබඳ ව්‍යාජ හැඟීමක් ලබා දෙයි. ඔබේ SUV රථය විශාල වන තරමට, ඉවත් කරන්නා වෙත යන මාර්ගය වැඩි වේ.

C ++ මඟින් වස්තුවේ ජීවන චක්‍ර කළමනාකරණය සමඟ ඔබව මුහුණට මුහුණ ලා තබයි. හොඳයි, ඒ සමඟ ගනුදෙනු කිරීමට ක්‍රම තිබේ ( ස්මාර්ට් පොයින්ටර්ස් පවුල, QT හි QObject සහ යනාදිය), නමුත් ඒ කිසිවක් GC වැනි 'ගින්දර සහ අමතක' ආකාරයෙන් භාවිතා කළ නොහැක: ඔබ සැමවිටම මතක හැසිරවීම මතකයේ තබා ගත යුතුය . වස්තුවක් විනාශ කිරීම ගැන ඔබ සැලකිලිමත් විය යුතු පමණක් නොව, එකම වස්තුව එක් වරකට වඩා විනාශ කිරීමෙන් වැළකී සිටිය යුතුය.

තවම බය නැද්ද? හරි: චක්‍රීය යොමු කිරීම් - ඒවා ඔබම හසුරුවන්න, මනුෂ්‍යය. මතක තබා ගන්න: එක් එක් වස්තුව හරියටම එක් වරක් මරා දමන්න, මළ සිරුරු අවුල් කරන, මියගිය අයව තනි කරන අයට අපි C ++ ධාවන කාලවලට කැමති නැත.

එබැවින්, ඔබේ ප්‍රශ්නයට ආපසු යන්න.

ඔබ ඔබේ වස්තුව වටිනාකමින්, ලක්ෂ්‍යයෙන් හෝ යොමු කිරීමකින් පසු කරන විට, ඔබ එම වස්තුව පිටපත් කරයි (මුළු වස්තුවම එය බයිට් කිහිපයක් හෝ විශාල දත්ත සමුදායක් වේවා - ඔබ ඒවා වළක්වා ගැනීමට සැලකිලිමත් වීමට තරම් බුද්ධිමත් ය. ඔබ කරන සෑම අවස්ථාවකම '='. වස්තුවේ සාමාජිකයන්ට ප්‍රවේශ වීම සඳහා ඔබ භාවිතා කරන්නේ '.' (තිත).

ඔබ ඔබේ වස්තුව දර්ශකයෙන් පසු කරන විට, ඔබ බයිට් කිහිපයක් (32-බිට් පද්ධති 4 ක්, 64-බිට් 64 මත) පිටපත් කරයි, එනම් - මෙම වස්තුවේ ලිපිනය. මෙය සෑම කෙනෙකුටම පෙන්වීමට, ඔබ සාමාජිකයින්ට ප්‍රවේශ වන විට මෙම විසිතුරු '->' ක්‍රියාකරු භාවිතා කරයි. නැතහොත් ඔබට '*' සහ '.' සංයෝජනය භාවිතා කළ හැකිය.

ඔබ යොමු කිරීම් භාවිතා කරන විට, එවිට ඔබට වටිනාකමක් මවා පෙන්වන දර්ශකය ලැබේ. එය දර්ශකයක්, නමුත් ඔබ සාමාජිකයින්ට '.' හරහා ප්‍රවේශ වේ.

ඔබේ මනස තවත් වරක් පුපුරවා හැරීමට: ඔබ කොමා මඟින් වෙන් කරන ලද විචල්‍යයන් කිහිපයක් ප්‍රකාශ කරන විට, (අත් දෙස බලන්න):

  • වර්ගය සෑම කෙනෙකුටම ලබා දී ඇත
  • අගය / දර්ශකය / යොමු විකරණකාරකය තනි වේ

උදාහරණයක්:

struct MyStruct
{
    int* someIntPointer, someInt; //here comes the surprise
    MyStruct *somePointer;
    MyStruct &someReference;
};

MyStruct s1; //we allocated an object on stack, not in heap

s1.someInt = 1; //someInt is of type 'int', not 'int*' - value/pointer modifier is individual
s1.someIntPointer = &s1.someInt;
*s1.someIntPointer = 2; //now s1.someInt has value '2'
s1.somePointer = &s1;
s1.someReference = s1; //note there is no '&' operator: reference tries to look like value
s1.somePointer->someInt = 3; //now s1.someInt has value '3'
*(s1.somePointer).someInt = 3; //same as above line
*s1.somePointer->someIntPointer = 4; //now s1.someInt has value '4'

s1.someReference.someInt = 5; //now s1.someInt has value '5'
                              //although someReference is not value, it's members are accessed through '.'

MyStruct s2 = s1; //'NO WAY' the compiler will say. Go define your '=' operator and come back.

//OK, assume we have '=' defined in MyStruct

s2.someInt = 0; //s2.someInt == 0, but s1.someInt is still 5 - it's two completely different objects, not the references to the same one

1
std::auto_ptrඅතහැර දමා ඇත, කරුණාකර එය භාවිතා නොකරන්න.
නීල්

2
ඉදිකිරීම්කරුවෙකුට විමර්ශන විචල්‍යය ඇතුළත් ආරම්භක ලැයිස්තුවක් ලබා නොදී ඔබට සාමාජිකයෙකු ලෙස යොමු කිරීමක් කළ නොහැකි බව විශ්වාසයි. (යොමු කිරීමක් වහාම ආරම්භ කළ යුතුය. ඉදිකිරීම්කරුගේ ශරීරය පවා එය සැකසීමට ප්‍රමාද වැඩියි, IIRC.)
cHao

21

C ++ හි, තොගයේ වෙන් කර ඇති වස්තූන් (වාරණයක් Object object;තුළ ප්‍රකාශයක් භාවිතා කරමින්) ජීවත් වන්නේ ඒවා ප්‍රකාශයට පත් කළ විෂය පථය තුළ පමණි. කේත වාරණය ක්‍රියාත්මක කිරීම අවසන් වූ විට ප්‍රකාශිත වස්තුව විනාශ වේ. ඔබ ගොඩවල් මත මතකය වෙන් කරන්නේ නම්, භාවිතා කරමින් Object* obj = new Object(), ඔබ ඇමතුමක් ගන්නා තෙක් ඒවා දිගටම ගොඩවල වාසය delete objකරයි.

වස්තුව ප්‍රකාශයට පත් කළ / වෙන් කළ කේත කොටසේ පමණක් නොව, වස්තුව භාවිතා කිරීමට මා කැමති විට මම ගොඩවල් මත වස්තුවක් නිර්මාණය කරමි.


6
Object objසැමවිටම තොගයේ නොමැත - උදාහරණයක් ලෙස ගෝලීය හෝ සාමාජික විචල්‍ය.
දහය

2
IghtLightnessRacesinOrbit මා සඳහන් කළේ බ්ලොක් එකක වෙන් කර ඇති වස්තූන් ගැන මිස ගෝලීය හා සාමාජික විචල්‍යයන් ගැන නොවේ. කාරණය එය පැහැදිලි නැත, දැන් එය නිවැරදි කර ඇත - පිළිතුරෙහි "වාරණයක් තුළ" එකතු කරන ලදි. එහි අසත්‍ය තොරතුරු දැන් බලාපොරොත්තු නොවේ :)
කාර්තික් කල්‍යාණසුන්දරම්

20

නමුත් මට හිතාගන්න බැහැ ඇයි අපි මේ වගේ භාවිතා කරන්නේ කියලා?

ඔබ භාවිතා කරන්නේ නම් ක්‍රියාකාරී ශරීරය තුළ එය ක්‍රියා කරන ආකාරය මම සංසන්දනය කරමි:

Object myObject;

ශ්‍රිතය ඇතුළත, myObjectමෙම ශ්‍රිතය නැවත පැමිණි පසු ඔබගේ විනාශය සිදුවනු ඇත. එබැවින් ඔබේ ශ්‍රිතයෙන් පිටත ඔබේ වස්තුව අවශ්‍ය නොවන්නේ නම් මෙය ප්‍රයෝජනවත් වේ. මෙම වස්තුව වත්මන් නූල් තොගයට දමනු ලැබේ.

ඔබ ක්‍රියාකාරී ශරීරය තුළ ලියන්නේ නම්:

 Object *myObject = new Object;

myObjectශ්‍රිතය අවසන් වූ පසු පෙන්වා දෙන වස්තු පන්තියේ උදාහරණය විනාශ නොවනු ඇත.

දැන් ඔබ ජාවා ක්‍රමලේඛකයෙක් නම්, දෙවන උදාහරණය ජාවා යටතේ වස්තු වෙන් කිරීම ක්‍රියාත්මක වන ආකාරය වෙත සමීප වේ. මෙම පේළිය: Object *myObject = new Object;java ට සමාන වේ : Object myObject = new Object();. වෙනස නම් ජාවා myObject යටතේ කසළ එකතු වන අතර c ++ යටතේ එය නිදහස් නොවනු ඇත, ඔබ කොතැනක හෝ පැහැදිලිවම 'මකන්න myObject;' එසේ නොමැතිනම් ඔබ මතක කාන්දුවීම් හඳුන්වා දෙනු ඇත.

C ++ 11 සිට ඔබට ගතික ප්‍රතිපාදන සඳහා ආරක්ෂිත ක්‍රම භාවිතා කළ හැකිය : new Object, shared_ptr / unique_ptr හි අගයන් ගබඩා කිරීමෙන්.

std::shared_ptr<std::string> safe_str = make_shared<std::string>("make_shared");

// since c++14
std::unique_ptr<std::string> safe_str = make_unique<std::string>("make_shared"); 

සිතියම් හෝ දෛශික වැනි බහාලුම්වල බොහෝ විට වස්තු ගබඩා කර ඇති අතර ඒවා ඔබේ වස්තූන්ගේ ආයු කාලය ස්වයංක්‍රීයව කළමනාකරණය කරයි.


1
then myObject will not get destroyed once function endsඑය නියත වශයෙන්ම සිදුවනු ඇත.
කක්ෂයේ සැහැල්ලු ධාවන තරඟ

6
myObjectවෙනත් ඕනෑම දේශීය විචල්‍යයක් මෙන් , දර්ශක නඩුවේදී, තවමත් විනාශ වනු ඇත. වෙනස එහි වටිනාකම බව ය පහිටුම් දක්වනය වස්තුව වන්නේ නැති වස්තුවක් සහ, ගොළු පහිටුම් දක්වනය විනාශ එහි pointee බලපාන නීතියක් නොවේ. එබැවින් වස්තුව නොනැසී පවතිනු ඇත.
cHao

ස්ථාවර, දේශීය විචල්යයන් (දර්ශකය ඇතුළත්) ඇත්ත වශයෙන්ම නිදහස් වනු ඇත - ඒවා සිරස්ව පවතී.
marcinj

13

තාක්ෂණික වශයෙන් එය මතක වෙන් කිරීමේ ගැටලුවක් වන අතර කෙසේ වෙතත් මෙහි තවත් ප්‍රායෝගික අංශ දෙකක් තිබේ. එය කාරණා දෙකක් සමඟ සම්බන්ධ වේ: 1) විෂය පථය, ඔබ දර්ශකයක් නොමැතිව වස්තුවක් නිර්වචනය කරන විට, එය අර්ථ දක්වා ඇති කේත වාරණයෙන් පසුව ඔබට තවදුරටත් එයට පිවිසිය නොහැකි අතර, ඔබ “නව” සමඟ දර්ශකයක් අර්ථ දක්වන්නේ නම් ඔබ එකම දර්ශකයේ "මකන්න" යනුවෙන් ඔබ හඳුන්වන තෙක් ඔබට මෙම මතකයට දර්ශකයක් ඇති ඕනෑම තැනක සිට ප්‍රවේශ විය හැකිය. 2) ඔබට ශ්‍රිතයකට තර්ක ඉදිරිපත් කිරීමට අවශ්‍ය නම් වඩාත් කාර්යක්ෂම වීමට ඔබට දර්ශකයක් හෝ යොමු කිරීමක් කළ යුතුය. ඔබ වස්තුවක් පසු කරන විට වස්තුව පිටපත් කරනු ලැබේ, මෙය විශාල මතකයක් භාවිතා කරන වස්තුවක් නම් මෙය CPU පරිභෝජනය කළ හැකිය (උදා: ඔබ දත්ත වලින් පිරුණු දෛශිකයක් පිටපත් කරයි). ඔබ දර්ශකයක් පසු කරන විට ඔබ සමත් වන්නේ එක් int එකකි (ක්‍රියාත්මක කිරීම අනුව නමුත් ඒවායින් බොහොමයක් එක් int වේ).

ඒ හැරෙන්නට ඔබ තේරුම් ගත යුතු කරුණක් නම් “නව” මඟින් යම් මොහොතක නිදහස් කළ යුතු ගොඩවල් මතකය මතකය වෙන් කරන බවයි. ඔබට "නව" භාවිතා කිරීමට අවශ්‍ය නොවන විට මම යෝජනා කරන්නේ "තොගයේ" නිත්‍ය වස්තු අර්ථ දැක්වීමක් භාවිතා කරන ලෙසයි.


6

හොඳයි ප්‍රධාන ප්‍රශ්නය වන්නේ වස්තුවට වඩා දර්ශකයක් භාවිතා කළ යුත්තේ ඇයි? මගේ පිළිතුර නම්, ඔබ කිසි විටෙකත් (පාහේ) වස්තුව වෙනුවට දර්ශකය භාවිතා නොකළ යුතුය, මන්ද C ++ වෙත යොමු කිරීම් ඇති බැවින් එය ආරක්ෂිත වන අතර පසුව දර්ශකයන් වන අතර දර්ශකයන්ගේ ක්‍රියාකාරිත්වය සහතික කරයි.

ඔබේ ප්‍රශ්නයේ ඔබ සඳහන් කළ තවත් දෙයක්:

Object *myObject = new Object;

එය ක්‍රියාත්මක වන්නේ කෙසේද? එය Objectවර්ගයේ දර්ශකයක් නිර්මාණය කරයි , එක් වස්තුවකට සරිලන පරිදි මතකය වෙන් කරයි, පෙරනිමි ඉදිකිරීම්කරු අමතයි, හොඳයි නේද? නමුත් ඇත්ත වශයෙන්ම එය එතරම් හොඳ නැත, ඔබ ගතිකව මතකය වෙන් කර ඇත්නම් (භාවිතා කළ යතුරුපදය new), ඔබට මතකය අතින් නිදහස් කළ යුතුය, එයින් අදහස් වන්නේ ඔබට තිබිය යුතු කේතයෙන්:

delete myObject;

මෙය ඩිස්ට්‍රැක්ටර් ලෙස හඳුන්වන අතර මතකය නිදහස් කරයි, කෙසේ වෙතත් විශාල ව්‍යාපෘති වලදී එක් නූල් මතකයක් නිදහස්ද නැද්ද යන්න සොයා ගැනීම දුෂ්කර විය හැකිය, නමුත් ඒ සඳහා ඔබට හවුල් දර්ශකයන් උත්සාහ කළ හැකිය , මේවා ක්‍රියාකාරීත්වය තරමක් අඩු කරයි, නමුත් එය සමඟ වැඩ කිරීම වඩා පහසුය ඔවුන්ට.


දැන් යම් හැඳින්වීමක් අවසන් වී නැවත ප්‍රශ්න කිරීමට යන්න.

ශ්‍රිතය අතර දත්ත මාරු කිරීමේදී වඩා හොඳ කාර්ය සාධනයක් ලබා ගැනීම සඳහා ඔබට වස්තු වෙනුවට දර්ශක භාවිතා කළ හැකිය.

බලන්න, ඔබ සතුව ඇත std::string(එය ද වස්තුවකි) සහ එහි ඇත්ත වශයෙන්ම බොහෝ දත්ත අඩංගු වේ, උදාහරණයක් ලෙස විශාල XML, දැන් ඔබට එය විග්‍රහ කළ යුතුය, නමුත් ඒ සඳහා ඔබට void foo(...)විවිධ ආකාරවලින් ප්‍රකාශ කළ හැකි ක්‍රියාකාරීත්වයක් ඇත:

  1. void foo(std::string xml); මෙම අවස්ථාවේදී ඔබ ඔබේ විචල්‍යයේ සිට ක්‍රියාකාරී තොගයට සියලුම දත්ත පිටපත් කරනු ඇත, එයට යම් කාලයක් ගතවනු ඇත, එබැවින් ඔබේ ක්‍රියාකාරිත්වය අඩු වනු ඇත.
  2. void foo(std::string* xml); මෙම අවස්ථාවෙහිදී, ඔබ දර්ශකය වස්තුව වෙත යොමු කරනු ඇත, size_tවිචල්‍යය පසු කරන වේගය මෙන් වේ, කෙසේ වෙතත් මෙම ප්‍රකාශය දෝෂ සහිත වේ, මන්ද ඔබට NULLදර්ශකය හෝ අවලංගු දර්ශකය පසු කළ හැකිය . පොයින්ටර්ස් සාමාන්‍යයෙන් භාවිතා කරනුයේ Cඑයට යොමු නොමැති නිසාය.
  3. void foo(std::string& xml); මෙහිදී ඔබ යොමු කිරීම සම්මත කරයි, මූලික වශයෙන් එය දර්ශකය පසු කිරීම හා සමාන වේ, නමුත් සම්පාදකයා යම් යම් දේ කරන අතර ඔබට අවලංගු යොමු කිරීමක් කළ නොහැක (ඇත්ත වශයෙන්ම අවලංගු යොමු කිරීමකින් තත්වය නිර්මාණය කළ හැකි නමුත් එය උපක්‍රමශීලී උපක්‍රමයකි).
  4. void foo(const std::string* xml); මෙන්න තත්පරයට සමානයි, හුදෙක් දර්ශක අගය වෙනස් කළ නොහැක.
  5. void foo(const std::string& xml); මෙන්න තුන්වන හා සමාන වේ, නමුත් වස්තු වටිනාකම වෙනස් කළ නොහැක.

මට තව දුරටත් සඳහන් කිරීමට අවශ්‍ය වන්නේ, ඔබ තෝරාගත් ප්‍රතිපාදන ක්‍රමය කුමක් වුවත් ( සම්මතnew හෝ නිතිපතා ) දත්ත සම්ප්‍රේෂණය කිරීමට ඔබට මෙම ක්‍රම 5 භාවිතා කළ හැකිය .


සඳහන් කළ යුතු තවත් දෙයක් නම්, ඔබ නිතිපතා වස්තුවක් නිර්මාණය කරන විට , ඔබ මතකය තොග වශයෙන් වෙන් කරයි, නමුත් ඔබ එය නිර්මාණය කරන අතරතුර newගොඩවල් වෙන් කරන්න. තොග වෙන් කිරීම වඩා වේගවත් ය, නමුත් එය ඇත්ත වශයෙන්ම විශාල දත්ත සමූහයක් සඳහා කුඩා වේ, එබැවින් ඔබට විශාල වස්තුවක් අවශ්‍ය නම් ඔබ ගොඩවල් භාවිතා කළ යුතුය, මන්ද ඔබට තොග පිටාර ගැලීම සිදුවිය හැකි නමුත් සාමාන්‍යයෙන් මෙම ගැටළුව STL බහාලුම් භාවිතයෙන් විසඳා මතක තබා ගන්න std::stringසමහර පිරිමි ළමයින්ට එය අමතකයි :)


5

ඔබට class Aඑහි අඩංගු බව කියමු. ඔබට පිටතින් class Bයම් කාර්යයක් ඇමතීමට අවශ්‍ය වූ විට ඔබ මෙම පන්තියට දර්ශකයක් ලබා ගන්නා අතර ඔබට අවශ්‍ය ඕනෑම දෙයක් කළ හැකි අතර එය ඔබගේ සන්දර්භය ද වෙනස් කරයිclass Bclass Aclass Bclass A

නමුත් ගතික වස්තුව සමඟ ප්‍රවේශම් වන්න


5

වස්තු සඳහා දර්ශක භාවිතා කිරීමෙන් බොහෝ වාසි ඇත -

  1. කාර්යක්ෂමතාව (ඔබ දැනටමත් පෙන්වා දී ඇති පරිදි). වස්තූන් ශ්‍රිත වෙත යොමු කිරීම යන්නෙන් අදහස් කරන්නේ වස්තුවේ නව පිටපත් නිර්මාණය කිරීමයි.
  2. තෙවන පාර්ශවීය පුස්තකාලවල වස්තු සමඟ වැඩ කිරීම. ඔබේ වස්තුව තෙවන පාර්ශවීය කේතයකට අයත් නම් සහ කතුවරුන් ඔවුන්ගේ වස්තූන් දර්ශකයන් හරහා පමණක් භාවිතා කිරීමට අදහස් කරන්නේ නම් (පිටපත් සාදන්නන් නැත) ඔබට මෙම වස්තුව වටා ගමන් කළ හැකි එකම ක්‍රමය දර්ශක භාවිතා කිරීමයි. වටිනාකම අනුව ගමන් කිරීම ගැටළු ඇති කළ හැකිය. (ගැඹුරු පිටපත් / නොගැඹුරු පිටපත් ගැටළු).
  3. වස්තුවට සම්පතක් තිබේ නම් සහ හිමිකාරිත්වය වෙනත් වස්තූන් සමඟ එකතු නොවිය යුතුය.

3

මෙය දීර් length වශයෙන් සාකච්ඡා කර ඇත, නමුත් ජාවාහි සෑම දෙයක්ම දර්ශකයකි. එය තොග සහ ගොඩවල් වෙන් කිරීම අතර වෙනසක් නොදක්වයි (සියලු වස්තූන් ගොඩවල් මත වෙන් කර ඇත), එබැවින් ඔබ දර්ශක භාවිතා කරන බව ඔබට වැටහෙන්නේ නැත. C ++ හි, ඔබේ මතක අවශ්‍යතා අනුව ඔබට මේ දෙක මිශ්‍ර කළ හැකිය. C ++ (duh) හි කාර්ය සාධනය සහ මතක භාවිතය වඩාත් නිර්ණායක වේ.


3
Object *myObject = new Object;

මෙය කිරීමෙන් මතක කාන්දු වීම වළක්වා ගැනීම සඳහා පැහැදිලිවම මකා දැමිය යුතු වස්තුවක් (ගොඩවල් මත) යොමු කිරීමක් නිර්මාණය වේ.

Object myObject;

මෙය කිරීමෙන් ස්වයංක්‍රීය වර්ගයේ (තොගයේ) වස්තුවක් (myObject) නිර්මාණය වන අතර එය වස්තුව (myObject) විෂය පථයෙන් බැහැර වූ විට ස්වයංක්‍රීයව මකා දැමෙනු ඇත.


1

දර්ශකයක් වස්තුවක මතක පිහිටීම කෙලින්ම සඳහන් කරයි. ජාවාට මේ වගේ දෙයක් නැහැ. ජාවා සතුව හැෂ් වගු හරහා වස්තුව පිහිටීම සඳහන් කරයි. මෙම යොමු කිරීම් සමඟ ඔබට ජාවාහි දර්ශක අංක ගණිතය වැනි කිසිවක් කළ නොහැක.

ඔබේ ප්‍රශ්නයට පිළිතුරු දීමට, එය ඔබගේ මනාපය පමණි. මම කැමතියි ජාවා වැනි සින්ටැක්ස් භාවිතා කිරීමට.


හැෂ් මේස? සමහර විට සමහර ජේවීඑම් වල නමුත් එය ගණන් නොගන්න.
සැන් ලින්ක්ස්

ජාවා සමඟ එන ජේවීඑම් ගැන කුමක් කිව හැකිද? ඇත්ත වශයෙන්ම ඔබට ජේවීඑම් එකක් මෙන් සෘජුවම දර්ශක භාවිතා කරන ජේවීඑම් එකක් හෝ දර්ශක ගණිතය කරන ක්‍රමයක් වැනි ඕනෑම දෙයක් ක්‍රියාත්මක කළ හැකිය. එය හරියට "සෙම්ප්‍රතිශ්‍යාව නිසා මිනිසුන් මිය නොයයි" යැයි පවසමින් ප්‍රතිචාරයක් ලබා ගැනීම "සමහර විට බොහෝ අය එය ගණන් නොගනී!" හ හ.
RioRicoRick

2
IoRioRicoRick HotSpot ජාවා යොමු දේශීය දර්ශකයන් ලෙස ක්‍රියාත්මක කරයි, docs.oracle.com/javase/7/docs/technotes/guides/vm/ බලන්න . මට පෙනෙන පරිදි JRockit එයම කරයි. ඔවුන් දෙදෙනාම OOP සම්පීඩනයට සහය දක්වයි, නමුත් කිසි විටෙකත් හැෂ්-මේස භාවිතා නොකරයි. කාර්ය සාධන ප්‍රතිවිපාක බොහෝ විට විනාශකාරී වනු ඇත. එසේම, "එය ඔබගේ මනාපය" යන්නෙන් ඇඟවෙන්නේ මේ දෙකම සමාන හැසිරීම් සඳහා හුදෙක් වෙනස් වාක්‍ය ඛණ්ඩයන් වන අතර ඇත්ත වශයෙන්ම ඒවා එසේ නොවේ.
මැක්ස් බැරැක්ලොග්


0

දර්ශකයන් සමඟ ,

  • මතකයට කෙලින්ම කතා කළ හැකිය.

  • දර්ශක හැසිරවීම මඟින් වැඩසටහනක මතක කාන්දු වීම වළක්වා ගත හැකිය.


4
" සී ++ හි, දර්ශක භාවිතා කරමින්, ඔබට ඔබේම වැඩසටහනක් සඳහා අභිරුචි කසළ එකතු කරන්නෙකු නිර්මාණය කළ හැකිය " එය භයානක අදහසක් සේ පෙනේ.
quant

0

දර්ශක භාවිතා කිරීමට එක් හේතුවක් වන්නේ සී ශ්‍රිත සමඟ අන්තර් ක්‍රියා කිරීමයි. තවත් හේතුවක් වන්නේ මතකය සුරැකීමයි; උදාහරණයක් ලෙස: විශාල දත්ත ප්‍රමාණයක් අඩංගු සහ ප්‍රොසෙසරයක් සහිත පිටපත්-සාදන්නෙකු ශ්‍රිතයක් වෙත යැවීම වෙනුවට, වස්තුවට දර්ශකයක් යොමු කරන්න, මතකය සහ වේගය ඉතිරි කර ගන්න, විශේෂයෙන් ඔබ ලූපයක සිටී නම්, කෙසේ වෙතත් a ඔබ සී-ශෛලීය අරාවක් භාවිතා නොකරන්නේ නම්, එම අවස්ථාවේ දී යොමු කිරීම වඩා හොඳ වනු ඇත.


0

මතක භාවිතය උපරිම මට්ටමක පවතින ප්‍රදේශවල, දර්ශකයන් ප්‍රයෝජනවත් වේ. නිදසුනක් ලෙස මිනිමැක්ස් ඇල්ගොරිතමයක් සලකා බලන්න, එහිදී පුනරාවර්තන චර්යාවන් භාවිතා කරමින් නෝඩ් දහස් ගණනක් ජනනය වන අතර පසුව ඒවා ක්‍රීඩාවේ ඊළඟ හොඳම පියවර තක්සේරු කිරීමට භාවිතා කරයි, අවලංගු කිරීමට හෝ නැවත සැකසීමට ඇති හැකියාව (ස්මාර්ට් පොයින්ටර් වල මෙන්) මතක පරිභෝජනය සැලකිය යුතු ලෙස අඩු කරයි. පුනරාවර්තන ඇමතුම මඟින් වටිනාකමක් ලබා දෙන තෙක් දර්ශක නොවන විචල්‍යය අවකාශයේ රැඳී සිටියි.


0

දර්ශකයේ එක් වැදගත් භාවිත අවස්ථාවක් මම ඇතුළත් කරමි. ඔබ කිසියම් වස්තුවක් මූලික පන්තියේ ගබඩා කරන විට, නමුත් එය බහුමාමක විය හැකිය.

Class Base1 {
};

Class Derived1 : public Base1 {
};


Class Base2 {
  Base *bObj;
  virtual void createMemerObects() = 0;
};

Class Derived2 {
  virtual void createMemerObects() {
    bObj = new Derived1();
  }
};

එබැවින් මෙම අවස්ථාවේදී ඔබට bObj සෘජු වස්තුවක් ලෙස ප්‍රකාශ කළ නොහැක, ඔබට දර්ශකය තිබිය යුතුය.


-4

"අවශ්‍යතාවය නව නිපැයුමේ මවයි." මම පෙන්වා දීමට කැමති වැදගත්ම වෙනස වන්නේ කේතීකරණයේ මගේම අත්දැකීම්වල ප්‍රති come ලයයි. සමහර විට ඔබ කාර්යයන් සඳහා වස්තු යැවිය යුතුය. එවැනි අවස්ථාවකදී, ඔබේ වස්තුව ඉතා විශාල පන්තියකට අයත් නම් එය වස්තුවක් ලෙස සම්මත කිරීමෙන් එහි තත්වය පිටපත් වනු ඇත (ඔබට අවශ්‍ය නොවනු ඇත .. සහ විශාල විය හැකිය) එමඟින් වස්තුව පිටපත් කිරීමේ පොදු කාර්යයක් සිදු වේ .එම ලක්ෂ්‍යය සවි කර ඇත 4-බයිට් ප්‍රමාණය (බිට් 32 උපකල්පනය කරයි). වෙනත් හේතු දැනටමත් ඉහත සඳහන් කර ඇත ...


14
යොමු දැක්වීමෙන් ඔබ කැමති විය යුතුය
bolov

2
std::string test;අප සතුව ඇති විචල්‍යයන් වැනි නියත-යොමු කිරීම් හරහා ගමන් කිරීම මම නිර්දේශ කරමි, void func(const std::string &) {}නමුත් ශ්‍රිතයට ආදාන වෙනස් කිරීමට අවශ්‍ය නම් මිස, දර්ශක භාවිතා කිරීමට මම නිර්දේශ කරමි (එවිට කේතය කියවන ඕනෑම කෙනෙකුට &එය
දැකගත

-7

දැනටමත් විශිෂ්ට පිළිතුරු බොහොමයක් ඇත, නමුත් මම ඔබට එක් උදාහරණයක් දෙන්නම්:

මට සරල අයිතම පන්තියක් ඇත:

 class Item
    {
    public: 
      std::string name;
      int weight;
      int price;
    };

මම ඔවුන්ගෙන් දෛශිකයක් සාදමි.

std::vector<Item> inventory;

මම අයිතම මිලියනයක් නිර්මාණය කර ඒවා දෛශිකයට තල්ලු කරමි. මම දෛශිකය නමින් වර්ග කර, පසුව කිසියම් අයිතමයක නමක් සඳහා සරල පුනරාවර්තන ද්විමය සෙවුමක් කරන්නෙමි. මම වැඩසටහන පරීක්ෂා කර, ක්‍රියාත්මක කිරීම අවසන් කිරීමට මිනිත්තු 8 කට වඩා ගත වේ. එවිට මම මගේ ඉන්වෙන්ටරි දෛශිකය එසේ වෙනස් කරමි:

std::vector<Item *> inventory;

... සහ මගේ අයිතම මිලියන වස්තු නව හරහා සාදන්න. මගේ කේතයේ මා විසින් සිදුකරන එකම වෙනස්කම් වන්නේ අයිතම සඳහා දර්ශක භාවිතා කිරීමයි, අවසානයේදී මතක පිරිසිදු කිරීම සඳහා මා එකතු කරන ලූපයක් හැර. එම වැඩසටහන තත්පර 40 ට අඩු කාලයක් තුළ ක්‍රියාත්මක වේ, නැතහොත් 10x වේග වැඩිවීමකට වඩා හොඳය. සංස්කරණය කරන්න: කේතය http://pastebin.com/DK24SPeW හි ඇත .


2
හොඳයි ඔබ එවකට දර්ශකයන් සංසන්දනය කරනවාද නැත්නම් ඔබ තවමත් සත්‍ය වස්තු සංසන්දනය කරනවාද? තවත් මට්ටමේ අවිනිශ්චිතතාවයකින් කාර්ය සාධනය වැඩි දියුණු කළ හැකි බවට මට බොහෝ සැකයි. කරුණාකර කේතය ලබා දෙන්න! ඔබ පසුව නිසි ලෙස පිරිසිදු කරනවාද?
ස්ටෙෆාන්

1
@stefan මම වර්ග කිරීම සහ සෙවීම යන දෙකටම වස්තු වල දත්ත (විශේෂයෙන් නම් ක්ෂේත්‍රය) සංසන්දනය කරමි. මම දැනටමත් ලිපියේ සඳහන් කර ඇති පරිදි මම නිසි ලෙස පිරිසිදු කරමි. වේගවත් වීමට හේතු සාධක දෙකක් නිසා විය හැකිය: 1) std :: vector push_back () වස්තු පිටපත් කරයි, එබැවින් දර්ශක අනුවාදයට අවශ්‍ය වන්නේ එක් වස්තුවකට එක් දර්ශකයක් පිටපත් කිරීම පමණි. මෙය ක්‍රියාකාරීත්වයට බහුවිධ බලපෑම් ඇති කරයි, මන්ද අඩු දත්ත පිටපත් කිරීම පමණක් නොව, දෛශික පන්තියේ මතක විබෙදුම අඩු වේ.
ඩැරන්

2
ඔබේ උදාහරණය සඳහා ප්‍රායෝගිකව කිසිදු වෙනසක් නොපෙන්වන කේතය මෙන්න: වර්ග කිරීම. දර්ශක කේතය වර්ග කිරීම සඳහා පමණක් නොවන දර්ශක කේතයට වඩා 6% වේගවත් වේ, නමුත් සමස්තයක් ලෙස එය දර්ශක නොවන කේතයට වඩා 10% මන්දගාමී වේ. ideone.com/G0c7zw
stefan

3
ප්රධාන වචනය: push_back. ඇත්ත වශයෙන්ම මෙම පිටපත්. emplaceඔබේ වස්තූන් නිර්මාණය කිරීමේදී ඔබ ස්ථානගතව සිටිය යුතුය (ඔබට ඒවා වෙනත් තැනක හැඹිලි කිරීමට අවශ්‍ය නොවේ නම්).
underscore_d

1
දර්ශකයන්ගේ දෛශික සෑම විටම පාහේ වැරදිය. අවවාද සහ වාසි සහ අවාසි විස්තර නොකර කරුණාකර ඒවා නිර්දේශ නොකරන්න. ඔබ එක් ප්‍රෝ එකක් සොයාගෙන ඇති බව පෙනේ, එය දුර්වල ලෙස කේතනය කරන ලද ප්‍රති-උදාහරණයක ප්‍රති
ence ලයක් පමණක් වන අතර
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.