C ++ ක්‍රමලේඛකයින් 'නව' භාවිතය අවම කළ යුත්තේ ඇයි?


884

මම රථයක්ද Stack පමාණය ප්රශ්නය සම්මත :: ලැයිස්තුව <සම්මත :: string> භාවිතා කරන විට සම්මත සමඟ මතකය කාන්දුවක් :: string , සහ අදහස් එක් මෙහෙම:

newබොහෝ දේ භාවිතා කිරීම නවත්වන්න . ඔබ කළ ඕනෑම තැනක ඔබ අලුතින් භාවිතා කළ කිසිදු හේතුවක් මට නොපෙනේ. ඔබට C ++ හි අගය අනුව වස්තු නිර්මාණය කළ හැකි අතර එය භාෂාව භාවිතා කිරීමේ විශාල වාසියකි.
ඔබ ගොඩේ සියල්ල වෙන් කළ යුතු නැත. ජාවා ක්‍රමලේඛකයෙකු
මෙන් සිතීම නවත්වන්න .

ඔහු එයින් අදහස් කරන්නේ කුමක්දැයි මට විශ්වාස නැත.

හැකි සෑම විටම C ++ හි අගය අනුව වස්තු නිර්මාණය කළ යුත්තේ ඇයි සහ එය අභ්‍යන්තරව ඇති කරන්නේ කුමක්ද?
මම පිළිතුර වැරදියට අර්ථකථනය කළාද?

Answers:


1047

බහුලව භාවිතා වන මතක විබෙදුම් ක්‍රම දෙකක් තිබේ: ස්වයංක්‍රීය වෙන් කිරීම සහ ගතික වෙන් කිරීම. පොදුවේ ගත් කල, එක් එක් සඳහා අනුරූප කලාපයක් ඇත: තොගය සහ ගොඩ.

සිරස්

තොගය සෑම විටම අනුපිළිවෙලින් මතකය වෙන් කරයි. එය එසේ කළ හැක්කේ ඔබට ප්‍රතිලෝම අනුපිළිවෙලින් මතකය මුදා හැරීමට අවශ්‍ය නිසාය (පළමු, අවසාන, අවසන්: FILO). බොහෝ ක්‍රමලේඛන භාෂාවල දේශීය විචල්‍යයන් සඳහා මතක වෙන් කිරීමේ තාක්ෂණය මෙයයි. එය ඉතා, ඉතා වේගවත් බැවින් එයට අවම පොත් තැබීමක් අවශ්‍ය වන අතර වෙන් කිරීම සඳහා ඊළඟ ලිපිනය ව්‍යංග වේ.

C ++ හි, මෙය ස්වයංක්‍රීය ආචයනය ලෙස හැඳින්වෙන්නේ විෂය පථය අවසානයේ ගබඩාව ස්වයංක්‍රීයව හිමිකම් කියන බැවිනි. වත්මන් කේත වාරණය ක්‍රියාත්මක කිරීම අවසන් වූ වහාම (භාවිතයෙන් වෙන් කිරීම {}), එම කොටසෙහි ඇති සියලුම විචල්‍යයන් සඳහා මතකය ස්වයංක්‍රීයව එකතු වේ. සම්පත් පිරිසිදු කිරීම සඳහා විනාශ කරන්නන් කැඳවන මොහොත මෙයයි .

ගොඩවල්

ගොඩවල් වඩාත් නම්‍යශීලී මතක විබෙදුම් ක්‍රමයක් සඳහා ඉඩ ලබා දේ. පොත් තැබීම වඩාත් සංකීර්ණ වන අතර ප්‍රතිපාදන මන්දගාමී වේ. කිසිදු ගම්ය නිදහස් අවස්ථාවක නොමැති නිසා, ඔබ මතක අතින්, භාවිතා නිදහස් කළ යුතුය deleteහෝ delete[]( freeසී.) කෙසේ වෙතත්, සංචිත මුදා හැරීමේ ලක්ෂ්‍යයක් නොමැතිකම ගොඩවල නම්‍යශීලීභාවයේ යතුරයි.

ගතික වෙන් කිරීම භාවිතා කිරීමට හේතු

සංචය භාවිතා කිරීම මන්දගාමී වන අතර මතක කාන්දු වීමකට හෝ මතක ඛණ්ඩනයකට තුඩු දිය හැකි වුවද, ගතික වෙන් කිරීම සඳහා හොඳ භාවිත අවස්ථා තිබේ, මන්ද එය සීමිත බැවිනි.

ගතික වෙන් කිරීම භාවිතා කිරීමට ප්‍රධාන හේතු දෙකක්:

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

  • වත්මන් බ්ලොක් එකෙන් ඉවත් වූ පසු මතකය වෙන් කිරීමට ඔබට අවශ්‍යය. උදාහරණයක් ලෙස, string readfile(string path)ගොනුවක අන්තර්ගතය නැවත ලබා දෙන ශ්‍රිතයක් ලිවීමට ඔබට අවශ්‍ය විය හැකිය . මෙම අවස්ථාවෙහිදී, තොගයට සම්පූර්ණ ගොනු අන්තර්ගතය රඳවා තබා ගත හැකි වුවද, ඔබට ශ්‍රිතයකින් ආපසු පැමිණ වෙන් කළ මතක කොටස තබා ගත නොහැක.

ගතික වෙන් කිරීම බොහෝ විට අනවශ්‍ය වන්නේ ඇයි

සී ++ හි ඩිස්ට්‍රැක්ටර් නමින් හැඳින්වෙන පිළිවෙලක් තිබේ. මෙම යාන්ත්‍රණය මඟින් සම්පත් වල ආයු කාලය විචල්‍යයක ආයු කාලය සමඟ පෙළගැස්වීමෙන් සම්පත් කළමනාකරණය කිරීමට ඉඩ ලබා දේ. මෙම තාක්ෂණය RAII ලෙස හැඳින්වෙන අතර එය C ++ හි කැපී පෙනෙන ලක්ෂ්‍යය වේ. එය සම්පත් වස්තු තුළට ඔතා. std::stringකදිම නිදසුනකි. මෙම ස්නිපටය:

int main ( int argc, char* argv[] )
{
    std::string program(argv[0]);
}

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

විශේෂයෙන්, මෙම ස්නිපටයේ එය ඇඟවුම් කරයි:

int main ( int argc, char* argv[] )
{
    std::string * program = new std::string(argv[0]);  // Bad!
    delete program;
}

අනවශ්‍ය ගතික මතක වෙන් කිරීමක් ඇත. වැඩසටහනට වැඩි ටයිප් කිරීමක් අවශ්‍ය වේ (!) සහ මතකය අවලංගු කිරීමට අමතක වීමේ අවදානම හඳුන්වා දෙයි. පෙනෙන ප්‍රතිලාභයක් නොමැතිව එය මෙය කරයි.

ඔබ හැකි සෑම විටම ස්වයංක්‍රීය ආචයනය භාවිතා කළ යුත්තේ ඇයි

මූලික වශයෙන්, අවසාන ඡේදය එය සාරාංශ කරයි. හැකි සෑම විටම ස්වයංක්‍රීය ආචයනය භාවිතා කිරීමෙන් ඔබේ වැඩසටහන් සිදු වේ:

  • ටයිප් කිරීමට වේගවත්;
  • ධාවනය වන විට වේගවත්;
  • මතක / සම්පත් කාන්දුවීම් වලට ඇති ඉඩකඩ අඩුය.

ප්‍රසාද ලකුණු

යොමු කරන ලද ප්රශ්නයේ දී, අතිරේක ගැටළු තිබේ. විශේෂයෙන්, පහත පන්තිය:

class Line {
public:
    Line();
    ~Line();
    std::string* mString;
};

Line::Line() {
    mString = new std::string("foo_bar");
}

Line::~Line() {
    delete mString;
}

ඇත්ත වශයෙන්ම පහත දැක්වෙන ඒවාට වඩා භාවිතා කිරීම වඩා අවදානම් සහිත ය:

class Line {
public:
    Line();
    std::string mString;
};

Line::Line() {
    mString = "foo_bar";
    // note: there is a cleaner way to write this.
}

හේතුව std::stringපිටපත් සාදන්නෙකු නිසියාකාරව නිර්වචනය කිරීමයි. පහත වැඩසටහන සලකා බලන්න:

int main ()
{
    Line l1;
    Line l2 = l1;
}

මුල් අනුවාදය භාවිතා කරමින්, මෙම වැඩසටහන deleteඑකම නූලක දෙවරක් භාවිතා කරන බැවින් එය බිඳ වැටෙනු ඇත . නවීකරණය කරන ලද අනුවාදය භාවිතා කරමින්, එක් එක් අවස්ථාවට Lineතමන්ගේම සංගීත නිදසුනක් හිමි වන අතර , සෑම එකක්ම තමන්ගේම මතකයක් ඇති අතර දෙකම වැඩසටහන අවසානයේ මුදා හරිනු ඇත.

වෙනත් සටහන්

ඉහත සියලු හේතු නිසා RAII හි පුළුල් භාවිතය C ++ හි හොඳම භාවිතයක් ලෙස සැලකේ. කෙසේ වෙතත්, අතිරේක ප්‍රතිලාභයක් ඇති අතර එය ක්ෂණිකව නොපෙනේ. මූලික වශයෙන්, එය එහි කොටස්වල එකතුවට වඩා හොඳයි. සමස්ත යාන්ත්‍රණයම සංයුක්ත වේ. එය පරිමාණය කරයි.

ඔබ Lineගොඩනැඟිලි අංගයක් ලෙස පන්තිය භාවිතා කරන්නේ නම් :

 class Table
 {
      Line borders[4];
 };

ඉන්පසු

 int main ()
 {
     Table table;
 }

std::stringඅවස්ථා හතරක්, අවස්ථා හතරක් Line, එක් Tableඅවස්ථාවක් සහ සියලු නූල්වල අන්තර්ගතය වෙන් කරන අතර සියල්ල ස්වයංක්‍රීයව නිදහස් වේ.


57
අවසානයේ RAII ගැන සඳහන් කිරීම සඳහා +1, නමුත් ව්‍යතිරේක ගැන යමක් තිබිය යුතුය.
ටෝබු

7
Ob ටෝබු: ඔව්, නමුත් මෙම ලිපිය දැනටමත් තරමක් දිගු වී ඇති අතර, එය OP හි ප්‍රශ්නය කෙරෙහි අවධානය යොමු කර තබා ගැනීමට මට අවශ්‍ය විය. මම බ්ලොග් සටහනක් හෝ යමක් ලිවීම අවසන් කර මෙතැනින් එයට සම්බන්ධ කරමි.
ඇන්ඩ්‍රේ කැරොන්

15
තොග වෙන් කිරීම සඳහා ඇති අවාසිය සඳහන් කිරීමට හොඳ අතිරේකයක් වනු ඇත (අවම වශයෙන් C ++ 1x තෙක්) - ඔබ පරිස්සම් නොවන්නේ නම් බොහෝ විට අනවශ්‍ය ලෙස දේවල් පිටපත් කළ යුතුය. උදා: Monsterපිටතට spits Treasureවෙත Worldඑය මිය ගිය විට. එහි Die()ක්‍රමයේදී එය ලෝකයට නිධානය එක් කරයි. world->Add(new Treasure(/*...*/))නිධානය මිය ගිය පසු එය ආරක්ෂා කර ගැනීමට එය වෙනත් ආකාරයකින් භාවිතා කළ යුතුය . විකල්ප නම් shared_ptr(අධික ලෙස මරා දැමිය හැකිය), auto_ptr(හිමිකාරිත්වය පැවරීම සඳහා දුර්වල අර්ථකථනය), අගය අනුව ගමන් කිරීම (නාස්තිකාර) සහ move+ unique_ptr(තවමත් පුළුල් ලෙස ක්‍රියාත්මක කර නොමැත).
kizzx2

7
තොග වෙන් කළ දේශීය විචල්‍යයන් ගැන ඔබ පැවසූ දේ ටිකක් නොමඟ යවන සුළු විය හැකිය. “තොගය” යන්නෙන් අදහස් කරන්නේ රාමු ගබඩා කරන ඇමතුම් තොගයයි . LIFO විලාසිතාවේ ගබඩා කර ඇත්තේ මෙම සිරස් රාමු ය. නිශ්චිත රාමුවක් සඳහා වන දේශීය විචල්‍යයන් වෙන් කරනු ලබන්නේ ඔවුන් ව්‍යුහයක සාමාජිකයන් ලෙස ය.
someguy

7
omesomeguy: ඇත්ත වශයෙන්ම, පැහැදිලි කිරීම පරිපූර්ණ නොවේ. ක්‍රියාත්මක කිරීමේ ප්‍රතිපාදන ප්‍රතිපත්තියේ නිදහස ඇත. කෙසේ වෙතත්, විචල්යයන් LIFO ආකාරයෙන් ආරම්භ කිරීම හා විනාශ කිරීම අවශ්ය වේ, එබැවින් ප්‍රතිසමයන් පවතී. මම හිතන්නේ නැහැ එය තව දුරටත් පිළිතුර අවුල් කරන වැඩක් කියලා.
ඇන්ඩ්‍රේ කැරොන්

172

මක්නිසාද යත් තොගය වේගවත් හා කාන්දු නොවන බැවිනි

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


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

33
Har චාලි නිවැරදිය. ස්වයංක්‍රීය විචල්‍යයන් වේගවත් වන අතර මෝඩ ප්‍රතිරෝධය වඩාත් නිවැරදි වනු ඇත.
ඔලිවර් චාල්ස්වර්ත්

28
Har චාලි: පන්ති අභ්‍යන්තරය දෙයාකාරයකින්ම සකස් කළ යුතුය. අවශ්‍ය අවකාශය වෙන් කිරීම මත සැසඳීම සිදු කෙරේ.
ඔලිවර් චාල්ස්වර්ත්

53
කැස්ස int x; return &x;
පීටර්චෙන්

16
වේගයෙන් ඔව්. නමුත් නිසැකවම මෝඩකමක් නොවේ. කිසිවක් මෝඩකමක් නොවේ. ඔබට StackOverflow ලබා ගත හැකිය :)
rxantos

107

හේතුව සංකීර්ණ වීමට හේතුව.

පළමුව, C ++ එකතු කරනු ලබන්නේ කසළ නොවේ. එබැවින් සෑම නව එකක් සඳහාම අනුරූප මකාදැමීමක් තිබිය යුතුය. ඔබ මෙම මකාදැමීමට අපොහොසත් වුවහොත් ඔබට මතක කාන්දුවක් ඇත. දැන්, මේ වගේ සරල සිද්ධියක් සඳහා:

std::string *someString = new std::string(...);
//Do stuff
delete someString;

මෙය සරලයි. නමුත් "දේවල් කරන්න" ව්‍යතිරේකයක් විසි කළහොත් කුමක් සිදුවේද? අපොයි: මතක කාන්දු වීම. "දේවල් කරන්න" returnකලින් නිකුත් කළහොත් කුමක් සිදුවේද ? අපොයි: මතක කාන්දු වීම.

මෙය සරලම අවස්ථාව සඳහා ය . ඔබ එම නූල යමෙකුට ආපසු ලබා දීමට සිදුවුවහොත්, දැන් ඔවුන් එය මකා දැමිය යුතුය. ඔවුන් එය තර්කයක් ලෙස සම්මත කරන්නේ නම්, එය ලබා ගන්නා පුද්ගලයා එය මකා දැමිය යුතුද? ඔවුන් එය මකා දැමිය යුත්තේ කවදාද?

නැතහොත්, ඔබට මෙය කළ හැකිය:

std::string someString(...);
//Do stuff

නැත delete. වස්තුව "තොගය" මත නිර්මාණය කරන ලද අතර එය විෂය පථයෙන් බැහැර වූ පසු එය විනාශ වේ. ඔබට වස්තුව ආපසු ලබා දිය හැකි අතර එමඟින් එහි අන්තර්ගතය ඇමතුම් ශ්‍රිතයට මාරු කරයි. ඔබට වස්තුව ශ්‍රිත වෙත යැවිය හැකිය (සාමාන්‍යයෙන් යොමු කිරීමක් හෝ සංයුක්ත යොමු කිරීමක් ලෙස : void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis). සහ එසේ ය.

සියල්ල නොමැතිව newසහ delete. මතකය අයිති කාටද යන්න හෝ එය මකා දැමීමට වගකිව යුත්තේ කවුරුන්ද යන්න පිළිබඳ ප්‍රශ්නයක් නොමැත. ඔබ එසේ කරන්නේ නම්:

std::string someString(...);
std::string otherString;
otherString = someString;

එය අවබෝධ කර ගත හැකි ය otherStringයන පිටපතක් තිබේ දත්ත පිළිබඳ someString. එය දර්ශකයක් නොවේ; එය වෙනම වස්තුවකි. ඒවා එකම අන්තර්ගතයක් තිබීම සිදුවිය හැකි නමුත් අනෙකට බලපෑමක් නොකර ඔබට එකක් වෙනස් කළ හැකිය:

someString += "More text.";
if(otherString == someString) { /*Will never get here */ }

අදහස බලන්න?


1
එම සටහනේ ... යම් වස්තුවක් ගතිකව වෙන් කර ඇත්නම් main(), වැඩසටහනේ කාලසීමාව සඳහා පවතී නම්, තත්වය හේතුවෙන් පහසුවෙන් තොගයේ නිර්මාණය කළ නොහැකි අතර, ඒ සඳහා ප්‍රවේශය අවශ්‍ය ඕනෑම කාර්යයකට යොමු කරයි. , මෙය වැඩසටහන් බිඳවැටීමකදී කාන්දු වීමට හේතු විය හැකිද, නැතහොත් එය ආරක්ෂිතද? වැඩසටහනේ සියලු මතකය අවලංගු කරන මෙහෙයුම් පද්ධතිය එය තර්කානුකූලව අවලංගු කළ යුතු බැවින් මම දෙවැන්න උපකල්පනය කරමි, නමුත් එය පැමිණි විට කිසිවක් උපකල්පනය කිරීමට මට අවශ්‍ය නැත new.
ජස්ටින් වේලාව - මොනිකා නැවත

4
Ust ජස්ටින් ටයිම් වැඩසටහනේ ජීවිත කාලය පුරාම රැඳී සිටීමට ගතිකව වෙන් කරන ලද වස්තූන්ගේ මතකය නිදහස් කිරීම ගැන ඔබ කරදර විය යුතු නැත. වැඩසටහනක් ක්‍රියාත්මක වන විට, මෙහෙයුම් පද්ධතිය ඒ සඳහා භෞතික මතකයක් හෝ අතථ්‍ය මතකයක් නිර්මාණය කරයි. අතථ්‍ය මතක අවකාශයේ ඇති සෑම ලිපිනයක්ම භෞතික මතකයේ ලිපිනයකට සිතියම් ගත කර ඇති අතර, වැඩසටහන පිටවන විට, එහි අථත්‍ය මතකයට සිතියම් ගත කර ඇති සියල්ල නිදහස් වේ. එබැවින්, වැඩසටහන සම්පූර්ණයෙන්ම පිටවන තාක් කල්, වෙන් කළ මතකය කිසි විටෙකත් මකා නොදැමීම ගැන කරදර විය යුතු නැත.
අයිමන් අල්-එරියානි

76

විසින් නිර්මාණය කරන ලද වස්තූන් newඅවසානයේ දී deleteඒවා කාන්දු නොවන පරිදි විය යුතුය . විනාශ කරන්නා කැඳවනු නොලැබේ, මතකය නිදහස් නොවනු ඇත. C ++ හි කසළ එකතු කිරීමක් නොමැති බැවින් එය ගැටළුවකි.

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

ස්මාර්ට් සූචක වැනි unique_ptr, shared_ptrමෙම කලිසමකින් යොමු ප්රශ්නය විසඳීම, නමුත් ඔවුන් කේතනය විනය අවශ්ය සහ අනෙකුත් හැකි ප්රශ්න (copyability, සමුද්දේශ වළළු, ආදිය) ඇත.

එසේම, දැඩි ලෙස බහු-තෙරපුම් අවස්ථා වලදී, newනූල් අතර මතභේදයට තුඩු දෙන කරුණකි; ඕනෑවට වඩා භාවිතා කිරීම සඳහා කාර්ය සාධන බලපෑමක් තිබිය හැකිය new. එක් එක් නූල් වලට තමන්ගේම තොගයක් ඇති හෙයින්, වස්තු සෑදීම අර්ථ දැක්වීම අනුව නූල්-දේශීය වේ.

වටිනාකමින් යුත් වස්තූන්ගේ අවාසිය නම් ධාරක ශ්‍රිතය නැවත පැමිණි පසු ඒවා මිය යාමයි - ඔබට නැවත ඇමතුම වෙත යොමු කිරීමක් කළ නොහැක, පිටපත් කිරීමෙන්, ආපසු පැමිණීමෙන් හෝ වටිනාකම අනුව ගමන් කිරීමෙන් පමණි.


9
+1. නැවත "නිර්මාණය කරන ලද වස්තූන් කාන්දු නොවන newලෙස අවසානයේදී විය යුතුය delete." - ඊටත් වඩා නරක නම්, new[]එයට අනුරූප විය යුතු අතර delete[], ඔබ delete new[]මතකය හෝ මතකය මත නම් ඔබට නිර්වචනය නොකළ හැසිරීමක් ලැබෙනු delete[] newඇත - සම්පාදකයින් ඉතා ස්වල්ප දෙනෙක් මේ ගැන අනතුරු අඟවයි (Cppcheck වැනි සමහර මෙවලම් හැකි විට ඒවා කරයි).
ටෝනි ඩෙල්රෝයි

3
OnyTonyDelroy සම්පාදකයාට මෙය අනතුරු ඇඟවිය නොහැකි අවස්ථා තිබේ. ශ්‍රිතයක් දර්ශකයක් නැවත ලබා දෙන්නේ නම්, එය නව (තනි මූලද්‍රව්‍යයක්) හෝ නව [] නම් එය නිර්මාණය කළ හැකිය.
fbafelipe

32
  • C ++ කිසිදු මතක කළමනාකරුවෙකු තනිවම සේවයේ යොදවන්නේ නැත. C #, Java වැනි වෙනත් භාෂාවල මතකය හැසිරවීමට කසළ එකතු කරන්නා සිටී
  • C ++ ක්‍රියාත්මක කිරීම් සාමාන්‍යයෙන් මතකය වෙන් කිරීම සඳහා මෙහෙයුම් පද්ධති ක්‍රියාකාරකම් භාවිතා කරන අතර ඕනෑවට වඩා නව / මකාදැමීම් මඟින් පවතින මතකය ඛණ්ඩනය කළ හැකිය
  • ඕනෑම යෙදුමක් සමඟ, මතකය නිතර භාවිතා කරන්නේ නම්, එය කලින් වෙන් කර අවශ්‍ය නොවන විට මුදා හැරීම සුදුසුය.
  • නුසුදුසු මතක කළමනාකරණය මඟින් මතක කාන්දු වීමට හේතු විය හැකි අතර එය සොයා ගැනීම දුෂ්කර ය. එබැවින් ක්‍රියාකාරී විෂය පථය තුළ සිරස් වස්තු භාවිතා කිරීම ඔප්පු කරන ලද තාක්‍ෂණයකි
  • සිරස් වස්තු භාවිතා කිරීමේ අවාසිය නම්, එය නැවත පැමිණීම, කාර්යයන් වෙත යාම වැනි වස්තූන්ගේ පිටපත් කිහිපයක් නිර්මාණය කිරීමයි. කෙසේ වෙතත් ස්මාර්ට් සම්පාදකයින් මෙම තත්වයන් පිළිබඳව හොඳින් දන්නා අතර ඒවා ක්‍රියාකාරීත්වය සඳහා හොඳින් සකසා ඇත
  • මතකය විවිධ ස්ථාන දෙකකින් වෙන් කර මුදා හරිනු ලැබුවහොත් එය C ++ හි ඇත්තෙන්ම වෙහෙසකරය. මුදා හැරීමේ වගකීම සැමවිටම ප්‍රශ්නයක් වන අතර බොහෝ දුරට අපි පොදුවේ ප්‍රවේශ විය හැකි දර්ශක, සිරස් වස්තු (හැකි උපරිම) සහ ස්වයංක්‍රීය_ප්ටර් (RAII වස්තු) වැනි ශිල්පීය ක්‍රම මත රඳා සිටිමු.
  • හොඳම දේ නම්, ඔබ මතකය පාලනය කර ඇති අතර නරකම දෙය නම් අපි යෙදුම සඳහා නුසුදුසු මතක කළමනාකරණයක් භාවිතා කරන්නේ නම් ඔබට මතකය පාලනය කළ නොහැකි වීමයි. මතක දූෂණය හේතුවෙන් සිදුවන බිඳවැටීම් ඉතාමත්ම දුෂ්කර හා සොයා ගැනීමට අපහසුය.

5
ඇත්ත වශයෙන්ම, මතකය වෙන් කරන ඕනෑම භාෂාවකට මතක කළමණාකරුවෙකු සිටී. බොහෝ ඒවා ඉතා සරල ය, එනම් int * x = malloc (4); int * y = malloc (4); ... පළමු ඇමතුම මඟින් මතකය වෙන් කරනු ඇත, හෝ මතකය සඳහා ඕඑස් ඉල්ලන්න, (සාමාන්‍යයෙන් 1k / 4k කුට්ටි වල) දෙවන ඇමතුම ඇත්ත වශයෙන්ම මතකය වෙන් නොකරයි, නමුත් එය වෙන් කළ අවසාන කැබැල්ලෙන් කොටසක් ඔබට ලබා දෙයි. IMO, කසළ එකතු කරන්නන් මතක කළමණාකරුවන් නොවේ, මන්ද එය හසුරුවන්නේ මතකය ස්වයංක්‍රීයව ඉවත් කිරීම පමණි. මතක කළමණාකරුවෙකු ලෙස හැඳින්වීමට, එය ගනුදෙනු කිරීම පමණක් නොව, මතකය වෙන් කිරීමද කළ යුතුය.
රාහුලි

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

C ++ "මෙහෙයුම් පද්ධති චර්යාවන් භාවිතා නොකරයි"; එය භාෂාවේ කොටසක් නොවේ, එය පොදු ක්‍රියාත්මක කිරීමකි. C ++ කිසිදු මෙහෙයුම් පද්ධතියක් නොමැතිව ක්‍රියාත්මක විය හැකිය.
einpoklum

22

හැකි තරම් නව දේවල් කිරීමට වැදගත් හේතු කිහිපයක් මග හැරී ඇති බව මට පෙනේ:

ක්‍රියාකරුට newනිශ්චිත නොවන ක්‍රියාත්මක කිරීමේ කාලයක් තිබේ

newඔබගේ ක්‍රියාවලියට මෙහෙයුම් පද්ධතියට නව භෞතික පිටුවක් වෙන් කිරීමට ඇමතුම හේතු විය හැක හෝ නොවිය හැක. ඔබ එය බොහෝ විට කරන්නේ නම් මෙය තරමක් මන්දගාමී විය හැකිය. නැතහොත් එයට දැනටමත් සුදුසු මතක ස්ථානයක් සුදානම් විය හැකිය, අපි නොදනිමු. ඔබේ වැඩසටහනට ස්ථාවර හා පුරෝකථනය කළ හැකි ක්‍රියාත්මක වීමේ කාලයක් අවශ්‍ය නම් (තත්‍ය කාලීන පද්ධතියක් හෝ ක්‍රීඩාවක් / භෞතික විද්‍යා සමාකරණයක් වැනි) newඔබේ කාල විවේචනාත්මක ලූපවලින් වැළකී සිටිය යුතුය .

ක්‍රියාකරු newයනු ව්‍යංග නූල් සමමුහුර්තකරණයකි

ඔව්, ඔබ මට ඇහුම්කන් දුන්නා, ඔබේ මෙහෙයුම් පද්ධතියට ඔබේ පිටු වගු අනුකූලද යන්න තහවුරු කර ගත යුතු අතර එවැනි ඇමතුමක් newඔබගේ නූල් ව්‍යංග මුටෙක්ස් අගුලක් ලබා ගැනීමට හේතු වේ. ඔබ newබොහෝ නූල් වලින් නිරන්තරයෙන් අමතන්නේ නම්, ඔබ ඇත්ත වශයෙන්ම ඔබේ නූල් අනුක්‍රමිකව සිදු කරයි (මම මෙය CPU 32 ක් සමඟ සිදු කර ඇත්තෙමි, සෑම එකක්ම newබයිට් සිය ගණනක් ලබා ගැනීමට පහර දෙමි, අපොයි!

මන්දගාමී, ඛණ්ඩනය, දෝෂ ඇතිවීමේ හැකියාව වැනි සෙසු පිළිතුරු දැනටමත් වෙනත් පිළිතුරු මගින් සඳහන් කර ඇත.


2
ස්ථානගත කිරීම නව / මකාදැමීම සහ මතකය අත තැබීමට පෙර දෙකම වළක්වා ගත හැකිය. නැතහොත් ඔබට මතකය ඔබ විසින්ම වෙන් කර / නිදහස් කර පසුව ඉදිකිරීම්කරු / විනාශ කරන්නා අමතන්න. සාමාන්‍යයෙන් std :: දෛශිකය ක්‍රියා කරන ආකාරය මෙයයි.
rxantos

1
xrxantos කරුණාකර OP කියවන්න, මෙම ප්‍රශ්නය අනවශ්‍ය මතක වෙන් කිරීම් වලක්වා ගැනීමයි. එසේම, ස්ථානගත කිරීම් මකාදැමීමක් නොමැත.
එමිලි එල්.

M එමිලි යනු OP අදහස් කළේ මෙයයි, මම සිතන්නේ:void * someAddress = ...; delete (T*)someAddress
xryl669

1
ක්‍රියාත්මක කිරීමේ වේලාවේදී තොග භාවිතා කිරීම නිර්ණායක නොවේ. ඔබ ඇමතුමක් mlock()හෝ ඒ හා සමාන දෙයක් හැර. මෙයට හේතුව පද්ධතිය මතකය අඩු මට්ටමක පැවතීම සහ තොගය සඳහා සූදානම් භෞතික මතක පිටු නොමැති වීම නිසා මෙහෙයුම් පද්ධතියට ඉදිරියට යාමට පෙර තැටියට හැඹිලි කිහිපයක් (පැහැදිලි අපිරිසිදු මතකයක්) මාරු කිරීමට හෝ ලිවීමට මෙහෙයුම් පද්ධතියට අවශ්‍ය විය හැකිය.
මිකෝ රන්ටලයිනන්

1
ikmikkorantalainen එය තාක්ෂණික වශයෙන් සත්‍ය නමුත් අඩු මතක තත්වයක් තුළ ඔබ ඔට්ටු අල්ලන විට ඔට්ටු ඇල්ලීම කෙසේ වෙතත් ක්‍රියා විරහිත වේ. එබැවින් ඔබට කළ හැකි කිසිවක් නොමැත. නව ඇමතුම් ලබා ගැනීම සාධාරණ වූ විට එය වළක්වා ගැනීමට උපදෙස් කෙසේ හෝ අවලංගු නොවේ.
එමිලි එල්.

21

පෙර-සී ++ 17:

ඔබ ප්‍රති result ලය ස්මාර්ට් පොයින්ටරයකින් ඔතා ගත්තද එය සියුම් කාන්දුවීම් වලට ගොදුරු වේ .

ස්මාර්ට් පොයින්ටර් වල වස්තු එතීමට මතක ඇති "ප්‍රවේශම් සහගත" පරිශීලකයෙකු සලකා බලන්න:

foo(shared_ptr<T1>(new T1()), shared_ptr<T2>(new T2()));

මෙම කේතය භයානක නොමැති නිසා ය කිසිදු සහතිකයක් එක්කෝ shared_ptrඉදිකර පෙර හෝ T1හෝ T2. ඒ නිසා, එක් නම් new T1()හෝ new T2()වෙනත් සාර්ථක පසු අසමත්, පසුව පළමු වස්තුව කිසිදු නිසා කාන්දු වනු ඇත shared_ptr, එය විනාශ සහ නිදහස් කිරීමට අවශ්යය පවතී.

විසඳුම: භාවිතා කරන්න make_shared.

පශ්චාත්-සී ++ 17:

මෙය තවදුරටත් ගැටළුවක් නොවේ: C ++ 17 මෙම මෙහෙයුම් වල අනුපිළිවෙලට බාධාවක් පනවයි, මේ අවස්ථාවේ දී සෑම ඇමතුමක්ම new()වහාම අනුරූපී ස්මාර්ට් පොයින්ටරය තැනීමෙන් පසුව කළ යුතු බව සහතික කරයි . මෙයින් ගම්‍ය වන්නේ, දෙවැන්න new()කැඳවන විට, පළමු වස්තුව දැනටමත් එහි ස්මාර්ට් පොයින්ටරයේ ඔතා ඇති බවට සහතික වී ඇති අතර, එමඟින් ව්‍යතිරේකයක් විසි වුවහොත් කාන්දුවීම් වලක්වනු ඇත.

සී ++ 17 විසින් හඳුන්වා දුන් නව ඇගයීම් නියෝගය පිළිබඳ වඩාත් සවිස්තරාත්මක පැහැදිලි කිරීමක් බැරී විසින් වෙනත් පිළිතුරකින් සපයන ලදී .

මෙය තවමත් C ++ 17 යටතේ ගැටළුවක් බව පෙන්වා දීම ගැන em රෙමී ලෙබියුට ස්තූතියි (අඩු වුවද): ඉදිකිරීම්කරුට එහි පාලන කොටස වෙන් කර විසි කිරීමට අසමත් විය හැකි අතර, ඒ සඳහා යොමු වූ දර්ශකය මකා නොදමනු ඇත.shared_ptr

විසඳුම: භාවිතා කරන්න make_shared.


5
වෙනත් විසඳුම: කිසි විටෙක එක් රේඛාවකට එක් වස්තුවකට වඩා ගතිකව වෙන් නොකරන්න.
ඇන්ටිමනි

3
Nt ඇන්ටිමනි: ඔව්, ඔබ දැනටමත් එකක් වෙන් කර ඇති විට එක් වස්තුවකට වඩා වැඩි ප්‍රමාණයක් වෙන් කිරීමට පෙළඹවීමක් ඇත.
user541686

1
මම හිතන්නේ මීට වඩා හොඳ පිළිතුරක් නම්, ව්‍යතිරේකයක් කැඳවනු ලැබුවහොත් කිසිවක් අල්ලා නොගන්නේ නම් ස්මාර්ට්_පීටීආර් කාන්දු වනු ඇති බවයි.
නටාලි ඇඩම්ස්

2
පශ්චාත් සී ++ 17 නඩුවේදී පවා, කාන්දුවීමක් සිදුවුවහොත් එය newසාර්ථක වුවහොත් පසුව සිදු වන shared_ptrඉදිකිරීම් අසාර්ථක වේ. std::make_shared()එයද විසඳනු ඇත
රෙමී ලෙබියු

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

17

බොහෝ දුරට, ඒ අය තමන්ගේ දුර්වලතා සාමාන්‍ය රීතියකට ඔසවා තබන අයෙකි. කිසිවක් වැරදි නැහැ අවතක්සේරුවට භාවිතා වස්තූන් නිර්මාණය සමඟ newක්රියාකරු. යම් තර්කයක් ඇති දෙය නම්, ඔබ යම් විනයකින් එය කළ යුතු බවයි: ඔබ යම් වස්තුවක් නිර්මාණය කළහොත් එය විනාශ වන බවට වග බලා ගත යුතුය.

එය කිරීමට ඇති පහසුම ක්‍රමය වන්නේ වස්තුව ස්වයංක්‍රීය ආචයනය තුළ නිර්මාණය කිරීමයි, එබැවින් එය විෂය පථයෙන් බැහැර වූ විට එය විනාශ කිරීමට C ++ දනී:

 {
    File foo = File("foo.dat");

    // do things

 }

දැන්, අවසාන වරහනෙන් පසු ඔබ එම කොටසින් වැටෙන විට, fooවිෂය පථයෙන් බැහැරව ඇති බව නිරීක්ෂණය කරන්න. C ++ ඔබ වෙනුවෙන් ස්වයංක්‍රීයව එහි dtor අමතනු ඇත. ජාවා මෙන් නොව, GC එය සොයා ගන්නා තෙක් ඔබ බලා සිටිය යුතු නැත.

ඔයා ලිව්වා නම්

 {
     File * foo = new File("foo.dat");

ඔබට එය පැහැදිලිවම ගැලපීමට අවශ්‍ය වනු ඇත

     delete foo;
  }

හෝ ඊටත් වඩා හොඳ නම්, ඔබේ File *“ස්මාර්ට් පොයින්ටර්” ලෙස වෙන් කරන්න . ඔබ ඒ ගැන සැලකිලිමත් නොවන්නේ නම් එය කාන්දුවීම් වලට තුඩු දිය හැකිය.

පිළිතුරම වැරදියට උපකල්පනය කරන්නේ ඔබ භාවිතා newනොකරන්නේ නම් ගොඩවල් මත වෙන් නොකරන්න; ඇත්ත වශයෙන්ම, C ++ හි ඔබ එය නොදනී. බොහෝ දුරට, ඔබ දන්නවා කුඩා මතක ප්‍රමාණයක්, එක් දර්ශකයක් කියන්න, නිසැකවම තොගය මත වෙන් කර ඇත. කෙසේ වෙතත්, ගොනුව ක්‍රියාත්මක කිරීම වැනි දෙයක් දැයි සලකා බලන්න

  class File {
    private:
      FileImpl * fd;
    public:
      File(String fn){ fd = new FileImpl(fn);}

පසුව FileImplඇත තවමත් අඩුක්කුව මුදලක් වෙන් කළ යුතු ය.

ඔව්, ඔබට විශ්වාසයි නම් හොඳයි

     ~File(){ delete fd ; }

පංතියේ ද; එය නොමැති, ඔබ ගොඩක් සිට මතකය කාන්දු වෙයි ඔබ නැත පවා නම් පෙනෙන සියලු දී ෙයාදා මත වෙන්.


4
ඔබ යොමු කරන ලද ප්‍රශ්නයේ කේතය දෙස බැලිය යුතුය. එම කේතයේ අනිවාර්යයෙන්ම බොහෝ දේ වැරදී ඇත.
ඇන්ඩ්‍රේ කැරොන්

7
new එක් එක් භාවිතා කිරීමේ කිසිදු වරදක් නොමැති බව මම එකඟ වෙමි , නමුත් ඔබ අදහස් දැක්වූ මුල් කේතය දෙස බැලුවහොත් newඑය අපයෝජනයට ලක් වේ. කේතය ලියා ඇත්තේ එය ජාවා හෝ සී # මෙන් වන අතර, newප්‍රායෝගිකව සෑම විචල්‍යයක් සඳහාම භාවිතා වේ, දේවල් තොගයේ තිබීම වඩා අර්ථවත් වන විට.
luke

5
සාධාරණ කරුණ. නමුත් පොදු අන්තරායන් වළක්වා ගැනීම සඳහා සාමාන්‍ය නීති සාමාන්‍යයෙන් ක්‍රියාත්මක වේ. මෙය පුද්ගල දුර්වලතාවයක් වුවත් නැතත්, මතක කළමනාකරණය මේ වගේ සාමාන්‍ය රීතියක් සහතික කිරීමට තරම් සංකීර්ණයි! :)
රොබන්_ෆෝර්ඩ්_ෆාන්_බෝයි

9
@Charlie: එම ප්රකාශය කරන්නේ නැහැ ඔබ භාවිතා නොකළ යුතු කියන්න new. ගතික වෙන් කිරීම සහ ස්වයංක්‍රීය ආචයනය අතර ඔබට තේරීමක් තිබේ නම් , ස්වයංක්‍රීය ආචයනය භාවිතා කරන්න.
ඇන්ඩ්‍රේ කැරොන්

8
Har චාර්ලි: භාවිතා කිරීමේ කිසිදු වරදක් නැත new, නමුත් ඔබ භාවිතා කරන්නේ නම් delete, ඔබ එය වැරදියි!
මැතිව් එම්

16

new()හැකි තරම් සුළු වශයෙන් භාවිතා නොකළ යුතුය . එය හැකි තරම් පරිස්සමින් භාවිතා කළ යුතුය . එය ප්‍රායෝගිකවාදය විසින් නියම කර ඇති පරිදි අවශ්‍ය සෑම විටම භාවිතා කළ යුතුය.

වස්තූන් ඒවායේ ව්‍යංග විනාශය මත රඳා පැවතීම සරල ආකෘතියකි. වස්තුවක අවශ්‍ය විෂය පථය එම ආකෘතියට ගැළපේ නම් new(), ඒ delete()හා සම්බන්ධ NULL දර්ශකයන් පරීක්ෂා කිරීම සමඟ භාවිතා කිරීම අවශ්‍ය නොවේ . ඔබට කෙටිකාලීන වස්තූන් විශාල ප්‍රමාණයක් ඇති අවස්ථාවකදී ගොඩවල් ඛණ්ඩනය වීමේ ගැටළු අවම කළ යුතුය.

කෙසේ වෙතත්, ඔබේ වස්තුවේ ආයු කාලය වත්මන් විෂය පථයෙන් ඔබ්බට විහිදීමට අවශ්‍ය නම් new()එය නිවැරදි පිළිතුරයි. delete()මකාදැමූ වස්තූන් සහ දර්ශකයන් භාවිතයෙන් පැමිණෙන අනෙකුත් සියලුම ගොචා භාවිතා කරමින්, ඔබ අමතන්නේ කවදාද සහ කෙසේද යන්න සහ NULL දර්ශකයන්ගේ හැකියාවන් පිළිබඳව අවධානය යොමු කිරීමට වග බලා ගන්න .


9
"ඔබේ වස්තුවේ ආයු කාලය වත්මන් විෂය පථයෙන් ඔබ්බට විස්තාරණය වීමට අවශ්‍ය නම් නව () යනු නිවැරදි පිළිතුරයි" ... මනාපයෙන් අගය අනුව ආපසු constනොඑන්නේ නම් හෝ යොමු නොවන හෝ දර්ශක මගින් ඇමතුම්-පරාස විචල්‍යයක් පිළිගන්නේ නැත්තේ ඇයි ...?
ටෝනි ඩෙල්රෝයි

2
Ony ටෝනි: ඔව්, ඔව්! යමෙකු යොමු කිරීම් ඉදිරිපත් කිරීම ගැන මම සතුටු වෙමි. මෙම ගැටළුව වළක්වා ගැනීම සඳහා ඒවා නිර්මාණය කරන ලදී.
නේතන් ඔස්මන්

OnyTonyD ... හෝ ඒවා ඒකාබද්ධ කරන්න: අගය අනුව ස්මාර්ට් පොයින්ටරයක් ​​ආපසු එවන්න. මෙම දුරකථන ඇමතුම සහ බොහෝ අවස්ථාවල දී (එනම් එහිදී ඒ ආකාරයෙන් make_shared/_uniqueද callee කිරීමට අවශ්ය නැහැ භාවිතා කළ හැකි,) newහෝ delete. මෙම පිළිතුරට සත්‍ය කරුණු මග හැරේ: (අ) සී ++ මඟින් RVO, චලන අර්ථකථන සහ ප්‍රතිදාන පරාමිතීන් වැනි දේ සපයයි - බොහෝ විට එයින් අදහස් කරන්නේ ගතිකව වෙන් කරන ලද මතකය නැවත ලබා දීමෙන් වස්තු නිර්මාණය කිරීම සහ ජීවිත කාලය දීර් extension කිරීම අනවශ්‍ය හා නොසැලකිලිමත් වන බවයි. )
underscore_d

14

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

Class var;

එය තොගයේ තබා ඇත.

ඔබ නිතරම අළුත් ගොඩවල් මත තැබූ වස්තුව විනාශ කිරීම ලෙස හැඳින්විය යුතුය. මෙය මතක කාන්දු වීමේ විභවය විවෘත කරයි. තොගයේ තැන්පත් කර ඇති වස්තූන් මතකය කාන්දු වීමට ඉඩක් නැත!


2
+1 "[ගොඩවල්] සාමාන්‍යයෙන් ඔබ ප්‍රසාරණය අපේක්ෂා කරන විට භාවිතා කරයි" - වැනි, std::stringහෝ std::map, ඔව්, දැඩි තීක්ෂ්ණ බුද්ධියකට එකතු කිරීම වැනි . මගේ ආරම්භක ප්‍රතික්‍රියාව වූයේ “වස්තුවක ආයු කාලය නිර්මාණය කිරීමේ කේතයේ විෂය පථයෙන් වෙන් constකිරීම” යන්නයි. එසේම. කර්මාන්තශාලා ක්‍රම වැනි වෙනත් ශබ්ද භාවිතයන් ඇත ....
ටෝනි ඩෙල්රෝයි

12

සංචය අධික ලෙස භාවිතා කිරීමෙන් වැළකී සිටීමට එක් වැදගත් හේතුවක් වන්නේ කාර්ය සාධනයයි - විශේෂයෙන් C ++ භාවිතා කරන පෙරනිමි මතක කළමනාකරණ යාන්ත්‍රණයේ ක්‍රියාකාරිත්වය සම්බන්ධ වේ. වෙන් ගොඩක් කරන්නේ, සුළු අයුරින් දී මුලුමනින් ම ඉක්මන් විය හැකි අතර, newසහ deleteපමණක් නොව මතක කට්ටි කිරීම සඳහා දැඩි නියෝගයක් නායකත්වය තොරව ඒකාකාර නො වන ප්රමාණයේ වස්තූන් මත, නමුත් එය ද වෙන් ඇල්ගොරිතමය පිලිබද හා පරම ඇතැම් අවස්ථාවල දී කාර්ය සාධන විනාශ කරන්න පුළුවන්.

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

කෙසේවෙතත්, ගැටලුව මුළුමනින්ම වළක්වා ගැනීම වඩා හොඳය. ඔබට එය තොගයේ තැබිය හැකි නම් එසේ කරන්න.


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

මතක තටාක යනු ඛණ්ඩනය වීම වළක්වා ගැනීම, අවලංගු කිරීම වේගවත් කිරීම (වස්තූන් දහස් ගණනක් සඳහා එක් වෙන් කිරීමක්) සහ බෙදා හැරීම වඩාත් ආරක්‍ෂිත කිරීමයි.
ලොතර්

10

මම හිතන්නේ පෝස්ටරයට You do not have to allocate everything on theheapවඩා කියන්නට අදහස් කළේ stack.

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


10

නව "ඕනෑවට වඩා" භාවිතා කිරීමේ අදහස සමඟ මම එකඟ නොවෙමි. මුල් පෝස්ටරයේ පද්ධති පන්ති සමඟ නව භාවිතය ටිකක් හාස්‍යජනක වුවද. ( int *i; i = new int[9999];ඇත්තටම? int i[9999];බොහෝ පැහැදිලි වේ.) මම හිතන්නේ වන commenter ගේ එළු ලබා දේ වේ.

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

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


සාමාන්‍යයෙන් නව / මකාදැමීම අරාවෙහි විශාලත්වය ඔබ නොදන්නා විට භාවිතා කරයි. ඇත්ත වශයෙන්ම std :: දෛශිකය ඔබ වෙනුවෙන් නව / මකා දමයි. ඔබ තවමත් ඒවා භාවිතා කරයි, නමුත් අගල std :: දෛශිකය. එබැවින් වර්තමානයේ එය භාවිතා කරනුයේ ඔබ අරාවෙහි විශාලත්වය නොදන්නා විට සහ යම් හේතුවක් නිසා std :: vector (කුඩා වන නමුත් තවමත් පවතින) හි ඉහළින් වළක්වා ගන්න.
rxantos

When you're working with your own classes/objects... ඔබට බොහෝ විට එසේ කිරීමට හේතුවක් නැත! Q වලින් ඉතා සුළු ප්‍රමාණයක් නිපුණ කේතකරුවන් විසින් බහාලුම් සැලසුම් කිරීම පිළිබඳ විස්තර මත ඇත. ඊට හාත්පසින්ම වෙනස්ව, අවපාත අනුපාතය යනු නවක වදය පවතින බව නොදන්නා නවකයන්ගේ ව්‍යාකූලත්වයයි - නැතහොත් 'ක්‍රමලේඛන' පා courses මාලා සඳහා සක්‍රීයව පැවරුම් ලබා දී ඇත, එහිදී උපදේශකයෙකු ඉල්ලා සිටින්නේ රෝදය ප්‍රතිනිර්මාණය කරන ලෙසයි. රෝදයක් යනු කුමක්ද සහ එය ක්‍රියා කරන්නේ ඇයිද යන්න ඉගෙන ගත්තේය . වඩාත් වියුක්ත ප්‍රතිපාදන ප්‍රවර්ධනය කිරීමෙන්, C ++ හට C හි නිමක් නැති 'සම්බන්ධිත ලැයිස්තුවක් සහිත segfault' වෙතින් අපව ගලවා ගත හැකිය; කරුණාකර, අපි එයට ඉඩ දෙමු .
underscore_d

" මුල් පෝස්ටරයේ පද්ධති පන්ති සමඟ නව භාවිතය ටිකක් හාස්‍යජනකය. ( int *i; i = new int[9999];? ඇත්ත වශයෙන්ම? int i[9999];වඩා පැහැදිලිය.)" ඔව්, එය වඩාත් පැහැදිලිය, නමුත් යක්ෂයාගේ උපදේශකයා ලෙස සෙල්ලම් කිරීමට, වර්ගය අනිවාර්යයෙන්ම නරක තර්කයක් නොවේ. මූලද්රව්ය 9999 සමඟ, මූලද්රව්ය 9999 ක් සඳහා ප්රමාණවත් තොගයක් නොමැති තද කාවැද්දූ පද්ධතියකට මට සිතාගත හැකිය: 9999x4 බයිට් ~ 40 kB, x8 ~ 80 kB වේ. එබැවින්, එවැනි පද්ධති විකල්ප මතකය භාවිතයෙන් එය ක්‍රියාත්මක කරයි යැයි උපකල්පනය කරමින් ගතික වෙන් කිරීම භාවිතා කිරීමට අවශ්‍ය විය හැකිය. එසේ වුවද, එය ගතික වෙන් කිරීම සාධාරණීකරණය කළ හැකිය new. a vectorයනු එම අවස්ථාවේ සැබෑ විසඳුම වනු ඇත
underscore_d

@Underscore_d සමඟ එකඟ වන්න - එය එතරම් හොඳ උදාහරණයක් නොවේ. මම මගේ තොගයට බයිට් 40,000 ක් හෝ 80,000 ක් එකතු නොකරමි. මම ඇත්ත වශයෙන්ම ඒවා ගොඩවල් මත වෙන් කරමි ( std::make_unique<int[]>()ඇත්ත වශයෙන්ම).
einpoklum

3

හේතු දෙකක්:

  1. මෙම අවස්ථාවේ දී එය අනවශ්ය ය. ඔබ ඔබේ කේතය අනවශ්‍ය ලෙස සංකීර්ණ කරයි.
  2. එය ගොඩවල් මත ඉඩ වෙන් කරයි, එයින් අදහස් කරන්නේ ඔබ deleteපසුව එය මතක තබා ගත යුතු බවයි, නැතහොත් එය මතක කාන්දුවක් ඇති කරයි.

2

newඅලුත් ය goto.

gotoමෙතරම් නින්දා අපහාස කිරීමට හේතුව මතක තබා ගන්න : එය ප්‍රවාහ පාලනය සඳහා ප්‍රබල, පහත් මට්ටමේ මෙවලමක් වන අතර, මිනිසුන් බොහෝ විට එය අනවශ්‍ය ලෙස සංකීර්ණ ආකාරවලින් භාවිතා කළ අතර එමඟින් කේතය අනුගමනය කිරීම දුෂ්කර විය. තවද, වඩාත් ප්‍රයෝජනවත් හා කියවීමට පහසුම රටා ව්‍යුහගත ක්‍රමලේඛන ප්‍රකාශනයන්හි කේතනය කර ඇත (උදා: forහෝ while); අවසාන බලපෑමක් ඇති කේතය බව ය gotoකිරීම සඳහා අවශ්ය වන මාර්ගය වෙනුවට දුර්ලභ වේ, ඔබ ලිවූ පරීක්ෂා කරන්නේ නම් goto,, ඔබට මීට දේවල් දරුණු ලෙස කරන්නේ (ඔබ නම් ඇත්තටම දන්නවා ඔයා මොනවද කරන්නේ කියලා.)

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

මම තර්ක කරන්නට newඇත නරක වඩා gotoයුගල කිරීමේ අවශ්යතාව නිසා, newසහ deleteප්රකාශ.

හරියට goto, ඔබ භාවිතා කළ යුතු යැයි ඔබ කවදා හෝ සිතන්නේ නම් new, ඔබ බොහෝ විට නරක දේ කරයි - විශේෂයෙන් ඔබ එසේ කරන්නේ පංතියක් ක්‍රියාත්මක කිරීමට පිටින් නම්, ජීවිතයේ අරමුණ වන්නේ ඔබට කළ යුතු ඕනෑම ගතික ප්‍රතිපාදන ඇතුළත් කිරීමයි.


මම ඔබට එකතු කරමි: "ඔබට මූලික වශයෙන් එය අවශ්‍ය නොවේ".
einpoklum

සමහර විට එය වෙනුවට භාවිතා කළ හැකි ඉදිකිරීමක් පිළිබඳ උදාහරණයක් දීමට උපකාරී වනු ඇත new.
gmatht

1

මූලික හේතුව වන්නේ ගොඩවල් මත ඇති වස්තූන් සෑම විටම සරල අගයන්ට වඩා භාවිතා කිරීමට සහ කළමනාකරණය කිරීමට අපහසු වීමයි. ඕනෑම බැරෑරුම් ක්‍රමලේඛකයෙකුගේ පළමු ප්‍රමුඛතාවය වන්නේ කියවීමට හා නඩත්තු කිරීමට පහසු කේත ලිවීමයි.

තවත් අවස්ථාවක් නම් අප භාවිතා කරන පුස්තකාලය වටිනාකම් අර්ථකථන සපයන අතර ගතික වෙන් කිරීම අනවශ්‍ය කිරීමයි. Std::stringහොඳ උදාහරණයක්.

කෙසේ වෙතත් වස්තු දිශානත කේතය සඳහා, දර්ශකයක් භාවිතා කිරීම - එයින් අදහස් කරන්නේ newඑය කලින්ම නිර්මාණය කිරීමට භාවිතා කිරීමයි - අත්‍යවශ්‍ය වේ. සම්පත් කළමනාකරණයේ සංකීර්ණත්වය සරල කිරීම සඳහා, ස්මාර්ට් පොයින්ටර් වැනි හැකි තරම් සරල කිරීමට මෙවලම් දුසිම් ගණනක් අප සතුව ඇත. වස්තූන් මත පදනම් වූ සුසමාදර්ශය හෝ සාමාන්‍ය පරාමිතිය අගය අර්ථ නිරූපණයන් උපකල්පනය newකරන අතර වෙනත් තැන්වල පෝස්ටර් සඳහන් කර ඇති ආකාරයට අඩු හෝ නැත .

සාම්ප්‍රදායික මෝස්තර රටා, විශේෂයෙන් GoF පොතේ සඳහන් කර ඇති newඒවා සාමාන්‍ය OO කේතයක් බැවින් බොහෝ දේ භාවිතා කරයි.


4
මෙය අගෞරවනීය පිළිතුරකි. For object oriented code, using a pointer [...] is a must: විකාර . ඔබ කුඩා උප කුලකයක් පමණක් සඳහන් කරමින් 'OO' අවප්රමානය නම්, බහුරූපතාෙව් - විකාර: යොමු ද වැඩ. [pointer] means use new to create it beforehand: විශේෂයෙන් විකාර : ස්වයංක්‍රීයව වෙන් කරන ලද වස්තූන් සඳහා යොමු කිරීම් හෝ දර්ශකයන් ගෙන යා හැකි අතර බහුඅවයවික වශයෙන් භාවිතා කරයි; මාව බලන්න . [typical OO code] use new a lot: සමහර විට පැරණි පොතක, නමුත් ඒ ගැන සැලකිලිමත් වන්නේ කවුද? යම් ආකාරයක නූතන C ++ eschews new/ අමු සූචක හැකි සෑම - සහ ය කිසිදු ආකාරයකින් එසේ කිරීමෙන් කිසිදු අඩු OO
underscore_d

1

ඉහත සඳහන් නිවැරදි පිළිතුරු සඳහා තවත් එක් කරුණක් නම්, එය ඔබ කරන්නේ කුමන ආකාරයේ වැඩසටහන් මතද යන්න මත රඳා පවතී. උදාහරණයක් ලෙස වින්ඩෝස් හි කර්නල් සංවර්ධනය වෙමින් පවතී -> තොගය දැඩි ලෙස සීමිත වන අතර පරිශීලක මාදිලියේ මෙන් පිටු දෝෂ ගැනීමට ඔබට නොහැකි වනු ඇත.

එවැනි පරිසරයන් තුළ, නව හෝ සී වැනි API ඇමතුම් වඩාත් කැමති වන අතර අවශ්‍ය වේ.

ඇත්ත වශයෙන්ම, මෙය හුදෙක් නීතියට ව්‍යතිරේකයකි.


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.