ස්ථිතික_ විකාශනය, ගතික_ විකාශනය, const_cast සහ නැවත අර්ථකථනය_ විකාශනය භාවිතා කළ යුත්තේ කවදාද?


2506

මේවායේ නිසි භාවිතයන් මොනවාද:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • සී විලාසිතාවේ වාත්තු (type)value
  • ක්‍රියාකාරී ශෛලියේ වාත්තු කිරීම type(value)

කුමන විශේෂිත අවස්ථා වලදී භාවිතා කළ යුතුද යන්න යමෙකු තීරණය කරන්නේ කෙසේද?



3
විවිධ වර්ගයේ කාස්ට් භාවිතා කිරීම පිළිබඳ ප්‍රයෝජනවත් කොන්ක්‍රීට් උදාහරණ සඳහා, ඔබට මෙම වෙනත් මාතෘකාවේ සමාන ප්‍රශ්නයකට පළමු පිළිතුර පරීක්ෂා කළ හැකිය .
තේමාන්කි

2
ඉහත ප්‍රශ්නයට ඔබට හොඳ පිළිතුරු සොයාගත හැකිය. නමුත් මම තවත් එක් කරුණක් මෙහි තැබීමට කැමැත්තෙමි, @ e.James "මෙම නව c ++ වාත්තු ක්‍රියාකරුවන්ට කළ හැකි කිසිවක් නැත.
BreakBadSP

ReBreakBadSP නව කාස්ට් වඩා හොඳ කේත කියවීමේ හැකියාව සඳහා පමණක් නොවේ . ඔවුන් එහි සිටින්නේ ඔවුන්ගේ සාරධර්ම වෙනුවට කොන්ස් ඉවත දැමීම හෝ පොයින්ටර්ස් දැමීම වැනි භයානක දේ කිරීම දුෂ්කර කිරීමට ය. static_cast වලට ac ස්ටයිල් කාස්ට් වලට වඩා භයානක දෙයක් කිරීමට ඇති ඉඩකඩ අඩුය!
FourtyTwo

OurFourtyTwo එකඟ විය
BreakBadSP

Answers:


2576

static_castඔබ භාවිතා කිරීමට උත්සාහ කළ යුතු පළමු කාස්ට් වේ. එය වර්ග (වැනි අතර ගම්ය පරිවර්ථනයන් වැනි දේවල් intකිරීමට float, හෝ පෙන්නුම් කරන්නක් void*), සහ එය ද පැහැදිලි පරිවර්තනය කාර්යයන් (හෝ ගම්ය අය) කතා කළ හැකිය. බොහෝ අවස්ථාවන්හීදී, පැහැදිලිව ප්‍රකාශ static_castකිරීම අවශ්‍ය නොවේ, නමුත් T(something)වාක්‍ය ඛණ්ඩය සමාන වන (T)somethingඅතර එය වළක්වා ගත යුතුය (පසුව වැඩි විස්තර). T(something, something_else)කෙසේ වෙතත්, A ආරක්ෂිත වන අතර, ඉදිකිරීම්කරු ඇමතීමට සහතික වේ.

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


const_castconstවිචල්යයක් ඉවත් කිරීමට හෝ එකතු කිරීමට භාවිතා කළ හැකිය ; වෙනත් C ++ කාස්ට් ඉවත් කිරීමට හැකියාවක් නැත (පවා නැත reinterpret_cast). කලින් constඅගය වෙනස් කිරීම නිර්වචනය කර ඇත්තේ මුල් විචල්‍යය නම් පමණක් බව සැලකිල්ලට ගැනීම වැදගත්ය const; constප්‍රකාශයට පත් නොකළ දෙයක් වෙත යොමු කිරීම ඉවත් කිරීමට ඔබ එය භාවිතා කරන්නේ නම් const, එය ආරක්ෂිත වේ. constඋදාහරණයක් ලෙස සාමාජික කාර්යයන් මත පැටවීමේදී මෙය ප්‍රයෝජනවත් වේ . constසාමාජික ශ්‍රිතයක් අධික ලෙස පැටවීම වැනි වස්තුවකට එකතු කිරීමට ද එය භාවිතා කළ හැකිය .

const_castඑය volatileඑතරම් සුලභ නොවූවත් ඒ හා සමානව ක්‍රියා කරයි .


dynamic_castබහුමාපකය හැසිරවීම සඳහා පමණක් භාවිතා වේ. ඔබට වෙනත් ඕනෑම පංති වර්ගයකට දර්ශකයක් හෝ යොමු කිරීමක් කළ හැකිය (බහුමාමක වර්ගයකට අවම වශයෙන් එක් අථත්‍ය ශ්‍රිතයක්වත් තිබේ, ප්‍රකාශිත හෝ උරුම වී ඇත). පහළට වාත්තු කරනවාට වඩා ඔබට එය භාවිතා කළ හැකිය - ඔබට පැත්තකට හෝ වෙනත් දාමයක් දැමිය හැකිය. මෙම dynamic_castඅපේක්ෂිත අරමුණ සොයා ගැනීමටත් හැකි නම් එය ආපසු ඇත. එය කළ නොහැකි නම්, එය nullptrදර්ශකයක් සම්බන්ධයෙන් නැවත පැමිණේ , නැතහොත් යොමු කිරීමකදී විසි std::bad_castකරයි.

dynamic_castසමහර සීමාවන් ඇත. උරුම ධූරාවලිය තුළ (ඊනියා 'භයානක දියමන්ති') එකම වර්ගයේ බහුවිධ වස්තූන් තිබේ නම් එය ක්‍රියා නොකරයි, ඔබ virtualඋරුමය භාවිතා නොකරන්නේ නම් . එයට යා හැක්කේ පොදු උරුමය හරහා පමණි - එය සැමවිටම ගමන් කිරීමට protectedහෝ privateඋරුමය හරහා අසමත් වනු ඇත . කෙසේ වෙතත්, මෙය කලාතුරකින් ගැටළුවක් වන අතර, එවැනි උරුමයන් දුර්ලභ වේ.


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


සී-ස්ටයිල් කාස්ට් සහ ශ්‍රිත-ශෛලීය වාත්තු යනු පිළිවෙලින් භාවිතා කරන (type)objectහෝ type(object)ක්‍රියාකාරී ලෙස සමාන වේ. ඒවා සාර්ථක වන පහත සඳහන් දේවලින් පළමුවැන්න ලෙස අර්ථ දැක්වේ:

  • const_cast
  • static_cast (ප්‍රවේශ සීමාවන් නොසලකා හැරියද)
  • static_cast (ඉහත බලන්න), පසුව const_cast
  • reinterpret_cast
  • reinterpret_cast, එවිට const_cast

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

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


17
ගතික_ විකාශනය බහුමාමක වර්ග සඳහා පමණි. ඔබට එය භාවිතා කිරීමට අවශ්‍ය වන්නේ ඔබ ව්‍යුත්පන්න පන්තියකට දැමූ විට පමණි. ඔබට නිශ්චිතවම ගතික_කාස්ට් හි ක්‍රියාකාරීත්වය අවශ්‍ය නොවන්නේ නම් ස්ථිතික_ විකාශය නිසැකවම පළමු විකල්පය වේ. එය පොදුවේ ආශ්චර්යමත් රිදී උණ්ඩ “වර්ග පරීක්ෂා කිරීමේ වාත්තු” නොවේ.
jalf

2
නියම පිළිතුර! එක් ඉක්මන් ප්‍රකාශයක්: ද්විත්ව ව්‍යුත්පන්න / යොමු කිරීම් ස්වයංක්‍රීයව ධූරාවලිය ඉහළට ඔසවා නොගන්නා හෙයින්, ඔබ ව්‍යුත්පන්න කර ඇති * සහ පාදම * තුළට දැමුවහොත් ධූරාවලිය ඉහළට ඔසවා තැබීමට ස්ථිතික_ විකාශනය අවශ්‍ය විය හැකිය. මිනිත්තු දෙකකට පෙර මට එවැනි (අවංකව, පොදු නොවේ) තත්වයක් ඇතිවිය. ;-)
bartgol

5
* "වෙනත් C ++ වාත්තු ඉවත් කිරීමට හැකියාවක් constනැත (පවා නැත reinterpret_cast)" ... ඇත්තටම? කුමක් ගැනද reinterpret_cast<int *>(reinterpret_cast<uintptr_t>(static_cast<int const *>(0)))?
user541686

29
ඉහත සඳහන් කළ වැදගත් විස්තරයක් නම් ස්ථිතික හෝ නැවත අර්ථකථනය_ විකාශනයට සාපේක්ෂව ගතික_කාස්ට් හට ධාවන කාල කාර්ය සාධන ද penalty ුවමක් ඇති බවයි. මෙය වැදගත් ය, උදා: තත්‍ය කාලීන මෘදුකාංග.
jfritz42

5
reinterpret_castඒපීඅයි හි පාරාන්ධ දත්ත වර්ග සමූහයක් සමඟ ගනුදෙනු කිරීමේදී එය බොහෝ විට තේරීමේ ආයුධය බව සඳහන් කිරීම වටී
පංති ඇටසැකිල්ල

333

dynamic_castඋරුම ධූරාවලියක් තුළ දර්ශක / යොමු පරිවර්තනය කිරීම සඳහා භාවිතා කරන්න .

static_castසාමාන්‍ය වර්ගයේ පරිවර්තනය සඳහා භාවිතා කරන්න .

reinterpret_castබිට් රටා පහත් මට්ටමේ නැවත අර්ථකථනය කිරීම සඳහා භාවිතා කරන්න . අතිශයින්ම පරිස්සමින් භාවිතා කරන්න.

const_castඉවත දැමීමට භාවිතා කරන්න const/volatile. ඔබ වැරදි-වැරදි API භාවිතා කරමින් හිර වී ඇත්නම් මිස මෙය වළක්වා ගන්න.


2
ගතික_ විකාශනය සමඟ ප්‍රවේශම් වන්න. එය RTTI මත රඳා පවතින අතර හවුල් පුස්තකාල සීමාවන් හරහා අපේක්ෂා කළ පරිදි මෙය ක්‍රියාත්මක නොවේ. හුදෙක් ඔබ ක්‍රියාත්මක කළ හැකි සහ බෙදාගත් පුස්තකාලයක් ස්වාධීනව ගොඩනඟා ඇති නිසා විවිධ ගොඩනැඟිලි හරහා RTTI සමමුහුර්ත කිරීමට ප්‍රමිතිගත ක්‍රමයක් නොමැත. Qt පුස්තකාලයේ මේ හේතුව නිසා qobject_cast <> වර්ග තිබේ.
user3150128

198

(න්‍යායාත්මක හා සංකල්පීය පැහැදිලි කිරීම් රාශියක් ඉහත දක්වා ඇත)

පහත කිහිපයකි ප්රායෝගික උදාහරණ මම භාවිතා කරන විට static_cast , dynamic_cast , const_cast , reinterpret_cast .

(පැහැදිලි කිරීම අවබෝධ කර ගැනීම සඳහා මෙය ද යොමු කරයි: http://www.cplusplus.com/doc/tutorial/typecasting/ )

static_cast:

OnEventData(void* pData)

{
  ......

  //  pData is a void* pData, 

  //  EventData is a structure e.g. 
  //  typedef struct _EventData {
  //  std::string id;
  //  std:: string remote_id;
  //  } EventData;

  // On Some Situation a void pointer *pData
  // has been static_casted as 
  // EventData* pointer 

  EventData *evtdata = static_cast<EventData*>(pData);
  .....
}

ගතික_ විකාශනය:

void DebugLog::OnMessage(Message *msg)
{
    static DebugMsgData *debug;
    static XYZMsgData *xyz;

    if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){
        // debug message
    }
    else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){
        // xyz message
    }
    else/* if( ... )*/{
        // ...
    }
}

const_cast:

// *Passwd declared as a const

const unsigned char *Passwd


// on some situation it require to remove its constness

const_cast<unsigned char*>(Passwd)

නැවත අර්ථකථනය_ විකාශනය:

typedef unsigned short uint16;

// Read Bytes returns that 2 bytes got read. 

bool ByteBuffer::ReadUInt16(uint16& val) {
  return ReadBytes(reinterpret_cast<char*>(&val), 2);
}

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

1
Reinterpret_cast හි අවසාන භාවිතය ගැන: මෙය භාවිතා කිරීමට සමාන static_cast<char*>(&val)නොවේද?
ලොරෙන්සෝ බෙලි

3
OreLorenzoBelli ඇත්ත වශයෙන්ම නැත. ඔබ එය උත්සාහ කළාද? දෙවැන්න වලංගු C ++ නොවන අතර සම්පාදනය අවහිර කරයි. static_castනිර්වචනය කළ පරිවර්තනයන්, උරුමය අනුව දෘශ්‍ය සම්බන්ධතාවය හෝ / සිට void *. අනෙක් සෑම දෙයක් සඳහාම, වෙනත් කැස්ට් තිබේ. reinterpret castඕනෑම char *වර්ගයකට ඕනෑම වස්තුවක නිරූපණය කියවීමට අවසර දෙනු ලැබේ - සහ එම මූල පදය ප්‍රයෝජනවත් වන එකම අවස්ථාව වන්නේ ක්‍රියාත්මක කිරීමේ උත්පාදක උත්පාදකයක් නොව / නිර්වචනය නොකළ හැසිරීමයි. නමුත් මෙය 'සාමාන්‍ය' පරිවර්තනයක් ලෙස නොසැලකේ, එබැවින් (සාමාන්‍යයෙන්) ඉතා ගතානුගතිකයින් විසින් එයට ඉඩ නොදේ static_cast.
underscore_d

2
ඔබ දත්ත සමුදායන් වැනි පද්ධති මෘදුකාංග සමඟ වැඩ කරන විට reinterpret_cast බහුලව දක්නට ලැබේ. බොහෝ අවස්ථාවන්හි ඔබ ඔබේම පිටු කළමණාකරුවෙකු ලියන අතර එය පිටුවෙහි ගබඩා කර ඇති දත්ත වර්ගය කුමක්ද යන්න පිළිබඳව කිසිදු අදහසක් නොමැති අතර එය අවලංගු දර්ශකයක් ලබා දෙයි. නැවත අර්ථකථනය කිරීම සහ එය ඔවුන්ට අවශ්‍ය ඕනෑම දෙයක් ලෙස අනුමාන කිරීම ඉහළ මට්ටම් දක්වා වේ.
සොහයිබ්

1
Const_cast උදාහරණයෙන් නිර්වචනය නොකළ හැසිරීම පෙන්නුම් කරයි. නියතයක් ලෙස ප්‍රකාශයට පත් කළ හැකි විචල්‍යයක් විස්ථාපනය කළ නොහැක. කෙසේ වෙතත්, නියත නොවන ලෙස ප්‍රකාශයට පත් කරන ලද විචල්‍යයක්, නියත යොමු කිරීමක් ලබා ගන්නා ශ්‍රිතයක් වෙත සම්ප්‍රේෂණය වන අතර, එම ශ්‍රිතයේ දී එය යූ.බී.
ජොහාන් ජෙරෙල්

99

ඔබ අභ්‍යන්තරය ගැන ටිකක් දන්නේ නම් එය උදව් වනු ඇත ...

static_cast

  • සී ++ සම්පාදකයා දැනටමත් පාවෙන වැනි පරිමාණ වර්ග අතරට පරිවර්තනය කරන්නේ කෙසේදැයි දනී. static_castඔවුන් සඳහා භාවිතා කරන්න .
  • ඔබ වර්ගය සිට ආගමට හරවා ගැනීමට සම්පාදක ඉල්ලන විට Aකිරීමට B, static_castඇමතුම් Bගේ ඉදිකිරීමටත් පසුකර Aparam ලෙස. විකල්පයක් ලෙස, Aපරිවර්තන ක්‍රියාකරුවෙකු සිටිය හැකිය (එනම් A::operator B()). Bඑවැනි ඉදිකිරීම්කරුවෙකු නොමැති නම් හෝ Aපරිවර්තන ක්‍රියාකරුවෙකු නොමැති නම්, ඔබට සම්පාදක කාල දෝෂයක් ලැබේ.
  • A සහ B උරුම ධූරාවලියේ (හෝ අවලංගු) තිබේ නම් වාත්තු A*කිරීම B*සැමවිටම සාර්ථක වේ.
  • ගොට්චා : ඔබ ව්‍යුත්පන්න දර්ශකයට පාදක දර්ශකය දැමුවද සත්‍ය වස්තුව සැබවින්ම ව්‍යුත්පන්න නොවේ නම් ඔබට දෝෂයක් ඇති නොවේ . ඔබට නරක දර්ශකයක් ලැබෙන අතර බොහෝ විට ධාවන වේලාවේදී සෙග්ෆෝල්ට් එකක් ලැබෙනු ඇත. එසේම A&වේ B&.
  • ගොට්චා : ව්‍යුත්පන්න සිට පාදම දක්වා හෝ වයිස්වර්සා නව පිටපතක් නිර්මාණය කරයි ! C # / Java වෙතින් පැමිණෙන පුද්ගලයින් සඳහා, මෙය විශාල පුදුමයක් විය හැකිය, මන්ද එහි ප්‍රති result ලය මූලික වශයෙන් ව්‍යුත්පන්න කර ඇති කැඩුණු වස්තුවකි.

ගතික_ විකාශනය

  • වාත්තු කිරීම වලංගු දැයි දැන ගැනීමට ගතික_කාස්ට් ධාවන කාල තොරතුරු භාවිතා කරයි. උදාහරණයක් ලෙස, (Base*)කිරීමට (Derived*)අවධානය යොමුකළ ව්යුත්පන්න වර්ගයේ ඇත්තටම නොවේ නම් අසමත් විය හැක.
  • මෙයින් අදහස් කරන්නේ, ස්ථිතික_ විකාශනයට සාපේක්ෂව ගතික_ විකාශනය ඉතා මිල අධික බවයි!
  • සඳහා A*කිරීමට B*, වාත්තු වලංගු නොවන නම් dynamic_cast nullptr හැරී යනු ඇත.
  • සඳහා A&කිරීමට B&කාස්ට් වලංගු නොවන නම් dynamic_cast bad_cast හැර විසි කරනු ඇත.
  • අනෙක් කාස්ට් මෙන් නොව, ධාවන වේලාව ඉහළින් පවතී.

const_cast

  • ස්ථිතික_ විකාශනයට නොනවත්වා කළ හැකි නමුත් එය වෙනත් මාර්ගයකට යා නොහැක. Const_cast හට ක්‍රම දෙකම කළ හැකිය.
  • මෙය ප්‍රයෝජනවත් වන එක් උදාහරණයක් නම්, යම් බහාලුමක් හරහා set<T>නැවත යෙදීමයි, එමඟින් එහි මූලද්‍රව්‍යයන් කොන්ස් ලෙස පමණක් ලබා දෙන අතර ඔබ එහි යතුර වෙනස් නොකරන බවට වග බලා ගන්න. කෙසේ වෙතත් ඔබේ අභිප්‍රාය වස්තුවෙහි ප්‍රධාන නොවන සාමාජිකයන් වෙනස් කිරීම නම් එය හරි විය යුතුය. ස්ථායිතාව ඉවත් කිරීමට ඔබට const_cast භාවිතා කළ හැකිය.
  • ඔබ ක්රියාත්මක කිරීමට අවශ්ය වන විට තවත් උදාහරණයක් T& SomeClass::foo()මෙන්ම const T& SomeClass::foo() const. කේත අනුපිටපත් වළක්වා ගැනීම සඳහා, එක් ශ්‍රිතයක අගය තවත් ක්‍රියාවකින් ආපසු ලබා දීම සඳහා ඔබට const_cast යෙදිය හැකිය.

නැවත අර්ථකථනය කරන්න

  • මෙය මූලික වශයෙන් පවසන්නේ මෙම මතක ස්ථානවල මෙම බයිට් රැගෙන එය ලබා දී ඇති වස්තුවක් ලෙස සිතන්න.
  • නිදසුනක් ලෙස, පාවෙන බිටු පෙනුම කෙබඳුදැයි බැලීමට ඔබට පාවෙන බයිට් 4 ක් int බයිට් 4 කට පැටවිය හැකිය.
  • නිසැකවම, වර්ගය සඳහා දත්ත නිවැරදි නොවේ නම්, ඔබට segfault ලබා ගත හැකිය.
  • මෙම වාත්තු කිරීම සඳහා ධාවන කාල සීමාවක් නොමැත.

මම පරිවර්තක ක්‍රියාකරු තොරතුරු එකතු කළෙමි, නමුත් තවත් කරුණු කිහිපයක් සවි කළ යුතු අතර මෙය යාවත්කාලීන කිරීම එතරම් පහසු යැයි මට හැඟෙන්නේ නැත. අයිතම නම්: 1. If you cast base pointer to derived pointer but if actual object is not really derived type then you don't get error. You get bad pointer and segfault at runtime.ඔබට යූබී ලැබෙන්නේ ඔබ වාසනාවන්ත නම් ධාවන වේලාවේදී සෙග්ෆෝල්ට් එකක් විය හැකිය. 2. හරස් වාත්තු කිරීමේදී ද ගතික කැස්ට් භාවිතා කළ හැකිය. 3. කොන්ස්ට් කැස්ට් සමහර අවස්ථාවල යූබී වලට හේතු විය හැක. mutableතාර්කික අනුකූලතාව ක්‍රියාත්මක කිරීම සඳහා භාවිතා කිරීම වඩා හොඳ තේරීමක් විය හැකිය.
ඒඩ්‍රියන්

1
D ඒඩ්‍රියන් ඔබ සෑම අතින්ම නිවැරදිය. පිළිතුර ලියා ඇත්තේ වැඩි වශයෙන් හෝ අඩු ආරම්භක මට්ටමේ සිටින පුද්ගලයින් සඳහා වන අතර අනෙක් සියලුම සංකූලතා mutable, හරස් වාත්තු කිරීම වැනි
දේවලින්

16

නැහැ මේ ඔබේ ප්රශ්නයට පිළිතුරු?

මම කිසි විටෙකත් භාවිතා කර නැති අතර reinterpret_cast, එය අවශ්‍ය වන නඩුවකට දිවීම නරක නිර්මාණයේ සුවඳක් නොවේදැයි කල්පනා කරන්න. මම වැඩ කරන කේත පදනමේ dynamic_castබොහෝ දේ භාවිතා වේ. මෙහි ඇති වෙනස static_castනම්, dynamic_castඔබට අවශ්‍ය දේ (වඩා ආරක්ෂිත) හෝ නොවිය හැකි (වැඩිපුර) විය හැකි ධාවන කාල පරීක්ෂාවකි ( msdn බලන්න ).


3
මම එක් අරමුණක් සඳහා reintrepret_cast භාවිතා කර ඇත්තෙමි - බිටු දෙගුණයකින් ලබා ගැනීම (මගේ වේදිකාවේ දිග තරම් දිග).
යෝෂුවා

2
COM වස්තු සමඟ වැඩ කිරීම සඳහා reinterpret_cast අවශ්‍ය වේ. CoCreateInstance () හි අවලංගු ** (අවසාන පරාමිතිය) හි ප්‍රතිදාන පරාමිතිය ඇත, එහිදී ඔබ ඔබේ දර්ශකය උදා: "INetFwPolicy2 * pNetFwPolicy2" ලෙස ප්‍රකාශයට පත් කරනු ඇත. එය සිදු කිරීම සඳහා, ඔබ නැවත අර්ථකථනය_ විකාශනය <අවලංගු **> (& pNetFwPolicy2) වැනි දෙයක් ලිවිය යුතුය.
සර්ජ් රොගාච්

1
සමහර විට වෙනස් ප්‍රවේශයක් ඇත, නමුත් මම reinterpret_castඅරාවකින් දත්ත කොටස් උපුටා ගැනීමට භාවිතා කරමි . නිදසුනක් ලෙස, char*විශාල බෆරයක් ඇසුරුම් කළ ද්විමය දත්ත වලින් පිරී තිබේ නම්, ඒ හරහා මට ගමන් කළ යුතු අතර විවිධ වර්ගවල ප්‍රාථමිකයන් ලබා ගත යුතුය. මේ වගේ දෙයක්:template<class ValType> unsigned int readValFromAddress(char* addr, ValType& val) { /*On platforms other than x86(_64) this could do unaligned reads, which could be bad*/ val = (*(reinterpret_cast<ValType*>(addr))); return sizeof(ValType); }
ජේම්ස් මැට්ටා

මම කවදාවත් භාවිතා කර නැත reinterpret_cast, ඒ සඳහා බොහෝ භාවිතයන් නොමැත.
පිකා තල්මසුන්ගේ විශාරද

පුද්ගලිකව මා දැක reinterpret_castඇත්තේ එක් හේතුවක් සඳහා පමණි. අමු වස්තු දත්ත දත්ත ගබඩාවක "බ්ලොබ්" දත්ත සමුදායකට ගබඩා කර ඇති බව මම දැක ඇත්තෙමි, පසුව දත්ත සමුදායෙන් දත්ත ලබා ගත් විට, reinterpret_castමෙම අමු දත්ත වස්තුව බවට හැරවීමට භාවිතා කරයි.
ImaginaryHuman072889

15

මෙතෙක් ලබා දී ඇති අනෙක් පිළිතුරු වලට අමතරව, අවශ්‍ය static_castනොවන පරිදි ප්‍රමාණවත් නොවන තැන අවිවාදිත උදාහරණයකි reinterpret_cast. නිමැවුම් පරාමිතියක විවිධ පංතිවල වස්තු වෙත යොමු කරන ශ්‍රිතයක් ඇතැයි සිතමු (ඒවා පොදු පාදක පන්තියක් බෙදා නොගනී). එවැනි ශ්‍රිතයක් සඳහා සැබෑ උදාහරණයක් වන්නේ CoCreateInstance()(අවසාන පරාමිතිය බලන්න, එය ඇත්ත වශයෙන්ම void**). මෙම ශ්‍රිතයෙන් ඔබ විශේෂිත වස්තු වර්ගයක් ඉල්ලයි යැයි සිතමු, එබැවින් ඔබ දර්ශකය සඳහා වර්ගය කල්තියා දන්නවා (ඔබ බොහෝ විට COM වස්තු සඳහා කරන). මෙම අවස්ථාවේ දී ඔබ ඔබගේ අවධානය යොමුකළ පෙන්නුම් කරන්නක් ප්රකාශ කළ නොහැකි void**සමග static_cast: ඔබට අවශ්ය reinterpret_cast<void**>(&yourPointer).

කේතයෙන්:

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    //static_cast<void**>(&pNetFwPolicy2) would give a compile error
    reinterpret_cast<void**>(&pNetFwPolicy2) );

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

#include <windows.h>
#include <netfw.h>
.....
INetFwPolicy2* pNetFwPolicy2 = nullptr;
void* tmp = nullptr;
HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr,
    CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),
    &tmp );
pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);

&static_cast<void*>(pNetFwPolicy2)ඒ වෙනුවට ඒ වගේ දෙයක් වැඩ කරන්නේ static_cast<void**>(&pNetFwPolicy2)නැද්ද?
jp48

9

වෙනත් පිළිතුරු අවසරයෙන් C ++ නීති ක්රීයාත්මක වන අතර සියලු වෙනස්කම් විස්තර අතර, මම ඔබ C ආකාරයේ නීති ක්රීයාත්මක වන භාවිතා කළ යුතු නෑ ඇයි කෙටි සටහනක් එකතු කිරීමට කැමැත්තෙමි (Type) varහා Type(var).

සී ++ ආරම්භකයින් සඳහා සී-ස්ටයිල් කැස්ට් යනු සී ++ කාස්ට් (ස්ථිතික_කාස්ට් <> (), ඩයිනමික්_කාස්ට් <> (), කොන්ස්ට්_කාස්ට් <> (), රීටෙන්ටර්ප්‍රෙස්ට්_කාස්ට් <> () ට වඩා සුපර්සෙට් මෙහෙයුමක් සේ පෙනේ, යමෙකුට සී ++ කාස්ට් වලට වඩා කැමති විය හැකිය. . ඇත්ත වශයෙන්ම සී-ස්ටයිල් කාස්ට් යනු සුපර්සෙට් සහ ලිවීමට කෙටි ය.

සී-ස්ටයිල් කැස්ට් වල ඇති ප්‍රධාන ගැටළුව නම්, ඔවුන් සංවර්ධකයින්ගේ සැබෑ අභිප්‍රාය සැඟවීමයි. ස්ථිතික_කාස්ට් <> () සහ ඩයිනමික්_කාස්ට් <> () විසින් සිදු කරන ලද සාමාන්‍යයෙන් ආරක්ෂිත වාත්තු සිට const_cast <> () වැනි භයානක කාස්ට් වෙත සී-ස්ටයිල් කාස්ට් වලට පාහේ කළ හැකි අතර, එහිදී කොන්ස්ට් විකරණකාරකය ඉවත් කළ හැකි අතර එමඟින් විචල්‍ය විචල්‍යයන් වෙනස් කළ හැකි අතර නැවත අර්ථකථනය_ විකාශනය කරන්න <> () මඟින් පූර්ණ සංඛ්‍යා අගයන් දර්ශකයන්ට නැවත අර්ථ දැක්විය හැකිය.

මෙන්න නියැදිය.

int a=rand(); // Random number.

int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.

int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.

int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.

*pa4=5; // Program crashes.

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

මෙන්න Bjarne Stroustrup's (C ++ හි කතුවරයා) පොතේ C ++ ක්‍රමලේඛන භාෂාව 4 වන සංස්කරණය - 302 පිටුව.

මෙම සී-ස්ටයිල් කාස්ට් නම් කරන ලද පරිවර්තන ක්‍රියාකරුවන්ට වඩා භයානක ය, මන්ද විශාල අංකනයක අංකනය හඳුනා ගැනීම දුෂ්කර වන අතර ක්‍රමලේඛකයා අදහස් කරන ආකාරයේ පරිවර්තනයක් පැහැදිලි නැත.


5

තේරුම් ගැනීමට, පහත කේත ස්නිපටය සලකා බලමු:

struct Foo{};
struct Bar{};

int main(int argc, char** argv)
{
    Foo* f = new Foo;

    Bar* b1 = f;                              // (1)
    Bar* b2 = static_cast<Bar*>(f);           // (2)
    Bar* b3 = dynamic_cast<Bar*>(f);          // (3)
    Bar* b4 = reinterpret_cast<Bar*>(f);      // (4)
    Bar* b5 = const_cast<Bar*>(f);            // (5)

    return 0;
}

පේළිය (4) පමණක් දෝෂයකින් තොරව සම්පාදනය කරයි. කිසියම් වස්තුවකට දර්ශකයක් සම්බන්ධයක් නැති ඕනෑම වස්තු වර්ගයක් බවට පරිවර්තනය කිරීමට භාවිතා කළ හැක්කේ reinterpret_cast පමණි .

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

C ++ වාත්තු භාවිතා කළ යුත්තේ කවදාද :

  • අගය පරිවර්තනය කරන සී-ස්ටයිල් කාස්ට් එකකට සමාන ලෙස ස්ථිතික_කාස්ට් භාවිතා කරන්න , නැතහොත් පන්තියක සිට එහි සුපිරි පන්තියට දර්ශකයක් පැහැදිලිව ඉහළට ඔසවා තැබීමට අපට අවශ්‍ය වූ විට.
  • Const සුදුසුකම් ඉවත් කිරීමට const_cast භාවිතා කරන්න .
  • පූර්ණ සංඛ්‍යා සහ වෙනත් දර්ශක වර්ග වෙත සහ ඉන් එහාට දර්ශක වර්ග අනාරක්ෂිත ලෙස පරිවර්තනය කිරීම සඳහා reinterpret_cast භාවිතා කරන්න . මෙය භාවිතා කරන්නේ අප කරන්නේ කුමක්ද යන්න අප දන්නා අතර අන්වර්ථකරණ ගැටළු තේරුම් ගන්නේ නම් පමණි.

3

static_castඑදිරිව dynamic_castඑදිරිව reinterpret_castඅභ්‍යන්තරිකයන් පහත් / ඉහළ මට්ටමේ දර්ශනයක්

මෙම පිළිතුරේ දී, මට අවශ්‍ය වන්නේ මෙම යාන්ත්‍රණ තුන කොන්ක්‍රීට් උඩු යටිකුරු / පහත් උදාහරණයකින් සංසන්දනය කර ඒවා සංසන්දනය කරන ආකාරය පිළිබඳ ස්ථිර අවබෝධයක් ලබා දීම සඳහා යටි පොයින්ටර්ස් / මතකය / එකලස් කිරීම සඳහා කුමක් සිදුවේද යන්න විශ්ලේෂණය කිරීමයි.

මෙම කුලයන් වෙනස් වන්නේ කෙසේද යන්න පිළිබඳව මෙය හොඳ අවබෝධයක් ලබා දෙනු ඇතැයි මම විශ්වාස කරමි:

  • static_cast: එක් ලිපිනයක් ධාවන වේලාවේදී (අඩු ධාවන කාල බලපෑම) ඕෆ්සෙට් කරන අතර පහත වැටීමක් නිවැරදි දැයි ආරක්‍ෂිත පරීක්‍ෂා නොකරයි.

  • dyanamic_cast: ක්‍රියාත්මක වන වේලාවේදී එකම ලිපිනය ඕෆ්සෙට් static_castකරනවාද, එසේම RTTI භාවිතා කර පහත වැටීමක් නිවැරදි දැයි මිල අධික ආරක්‍ෂිත පරීක්‍ෂණයක්ද?

    nullptrඅවලංගු අවතක්සේරු කිරීමක් පෙන්නුම් කරන නැවත පැමිණීම පරීක්ෂා කිරීමෙන් මූලික පන්තියේ දර්ශකයක් ධාවන වේලාවේ දී ලබා දී ඇති වර්ගයක් දැයි විමසීමට මෙම ආරක්‍ෂිත පරීක්‍ෂණය මඟින් ඉඩ ලබා දේ .

    එමනිසා, ඔබේ කේතයට ඒ සඳහා පරික්‍ෂා කර nullptrවලංගු නොවන ක්‍රියාමාර්ගයක් ගැනීමට නොහැකි නම්, ඔබ භාවිතා කළ යුත්තේ static_castගතික වාත්තු කිරීම වෙනුවට ය.

    ක ඉවත්වීම ඔබගේ කේතය ගත හැකි එකම පියවර වන්නේ නම්, සමහර විට ඔබ පමණක් සක්රිය කිරීමට අවශ්ය dynamic_castදෝශනිරාකරණ වාර්ථා, ඇල්ම, ( -NDEBUG), සහ භාවිතා static_castකරන්න, නැතහොත් උදා: මෙහි සිදු ලෙස ඔබේ වේගයෙන් ලකුණු වේගය අඩු නොවේ.

  • reinterpret_cast: ධාවන වේලාවේදී කිසිවක් නොකරයි, ලිපිනය පවා ඕෆ්සෙට් නොවේ. දර්ශකය නිවැරදි වර්ගයට හරියටම යොමු කළ යුතුය, මූලික පන්තියක් පවා ක්‍රියා නොකරයි. අමු බයිට් ප්‍රවාහයන් සම්බන්ධ නොවන්නේ නම් ඔබට සාමාන්‍යයෙන් මෙය අවශ්‍ය නොවේ.

පහත කේත උදාහරණය සලකා බලන්න:

main.cpp

#include <iostream>

struct B1 {
    B1(int int_in_b1) : int_in_b1(int_in_b1) {}
    virtual ~B1() {}
    void f0() {}
    virtual int f1() { return 1; }
    int int_in_b1;
};

struct B2 {
    B2(int int_in_b2) : int_in_b2(int_in_b2) {}
    virtual ~B2() {}
    virtual int f2() { return 2; }
    int int_in_b2;
};

struct D : public B1, public B2 {
    D(int int_in_b1, int int_in_b2, int int_in_d)
        : B1(int_in_b1), B2(int_in_b2), int_in_d(int_in_d) {}
    void d() {}
    int f2() { return 3; }
    int int_in_d;
};

int main() {
    B2 *b2s[2];
    B2 b2{11};
    D *dp;
    D d{1, 2, 3};

    // The memory layout must support the virtual method call use case.
    b2s[0] = &b2;
    // An upcast is an implicit static_cast<>().
    b2s[1] = &d;
    std::cout << "&d           " << &d           << std::endl;
    std::cout << "b2s[0]       " << b2s[0]       << std::endl;
    std::cout << "b2s[1]       " << b2s[1]       << std::endl;
    std::cout << "b2s[0]->f2() " << b2s[0]->f2() << std::endl;
    std::cout << "b2s[1]->f2() " << b2s[1]->f2() << std::endl;

    // Now for some downcasts.

    // Cannot be done implicitly
    // error: invalid conversion from ‘B2*’ to ‘D*’ [-fpermissive]
    // dp = (b2s[0]);

    // Undefined behaviour to an unrelated memory address because this is a B2, not D.
    dp = static_cast<D*>(b2s[0]);
    std::cout << "static_cast<D*>(b2s[0])            " << dp           << std::endl;
    std::cout << "static_cast<D*>(b2s[0])->int_in_d  " << dp->int_in_d << std::endl;

    // OK
    dp = static_cast<D*>(b2s[1]);
    std::cout << "static_cast<D*>(b2s[1])            " << dp           << std::endl;
    std::cout << "static_cast<D*>(b2s[1])->int_in_d  " << dp->int_in_d << std::endl;

    // Segfault because dp is nullptr.
    dp = dynamic_cast<D*>(b2s[0]);
    std::cout << "dynamic_cast<D*>(b2s[0])           " << dp           << std::endl;
    //std::cout << "dynamic_cast<D*>(b2s[0])->int_in_d " << dp->int_in_d << std::endl;

    // OK
    dp = dynamic_cast<D*>(b2s[1]);
    std::cout << "dynamic_cast<D*>(b2s[1])           " << dp           << std::endl;
    std::cout << "dynamic_cast<D*>(b2s[1])->int_in_d " << dp->int_in_d << std::endl;

    // Undefined behaviour to an unrelated memory address because this
    // did not calculate the offset to get from B2* to D*.
    dp = reinterpret_cast<D*>(b2s[1]);
    std::cout << "reinterpret_cast<D*>(b2s[1])           " << dp           << std::endl;
    std::cout << "reinterpret_cast<D*>(b2s[1])->int_in_d " << dp->int_in_d << std::endl;
}

සම්පාදනය කරන්න, ධාවනය කරන්න සහ විසුරුවා හරින්න:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
setarch `uname -m` -R ./main.out
gdb -batch -ex "disassemble/rs main" main.out

එහිදී setarchඇත ආබාධිත ASLR භාවිතා පහසු ලකුණු සන්සන්දනය කිරීම කළ යුතු බව ය.

හැකි ප්‍රතිදානය:

&d           0x7fffffffc930
b2s[0]       0x7fffffffc920
b2s[1]       0x7fffffffc940
b2s[0]->f2() 2
b2s[1]->f2() 3
static_cast<D*>(b2s[0])            0x7fffffffc910
static_cast<D*>(b2s[0])->int_in_d  1
static_cast<D*>(b2s[1])            0x7fffffffc930
static_cast<D*>(b2s[1])->int_in_d  3
dynamic_cast<D*>(b2s[0])           0
dynamic_cast<D*>(b2s[1])           0x7fffffffc930
dynamic_cast<D*>(b2s[1])->int_in_d 3
reinterpret_cast<D*>(b2s[1])           0x7fffffffc940
reinterpret_cast<D*>(b2s[1])->int_in_d 32767

දැන්, මෙහි සඳහන් කර ඇති පරිදි: https://en.wikipedia.org/wiki/Virtual_method_table අථත්ය ක්රම ඇමතුම් කාර්යක්ෂමව සහය දැක්වීම සඳහා, මතක දත්ත ව්යුහයD සමාන විය යුතුය:

B1:
  +0: pointer to virtual method table of B1
  +4: value of int_in_b1

B2:
  +0: pointer to virtual method table of B2
  +4: value of int_in_b2

D:
  +0: pointer to virtual method table of D (for B1)
  +4: value of int_in_b1
  +8: pointer to virtual method table of D (for B2)
 +12: value of int_in_b2
 +16: value of int_in_d

ප්රධාන කාරණය නම්, එහි මතක දත්ත ව්යුහය Dතුළ මතක ව්යුහය අඩංගු වේB1B2 අභ්‍යන්තරව හා අභ්‍යන්තරව වීමයි .

එබැවින් අපි තීරණාත්මක නිගමනයකට එළඹෙමු:

උඩු යටිකුරු කළ හෝ පහත් වූ විට අවශ්‍ය වන්නේ දර්ශක අගය සම්පාදනය කරන වේලාවේ දන්නා අගයකින් මාරු කිරීමයි

මේ ආකාරයෙන්, Dමූලික වර්ගයේ අරාව වෙත ගිය විට , වාත්තු වර්ගය ඇත්ත වශයෙන්ම එම ඕෆ්සෙට් ගණනය කර B2මතකයේ වලංගු යැයි පෙනෙන දෙයක් පෙන්වා දෙයි :

b2s[1] = &d;

මේ සඳහා vtable ඇති බව හැර Dඒ වෙනුවට අතර B2, එබැවින් සියලු අථත්‍ය ඇමතුම් විනිවිදභාවයෙන් ක්‍රියා කරයි.

දැන්, අපට අවසාන වශයෙන් යතුරු ලියනය කිරීම සහ අපගේ සංයුක්ත උදාහරණය විශ්ලේෂණය කිරීම වෙත ආපසු යා හැකිය.

Stdout නිමැවුමෙන් අපට පෙනෙන්නේ:

&d           0x7fffffffc930
b2s[1]       0x7fffffffc940

එම නිසා, එහි static_castසිදු කර ඇති ව්‍යංගයෙන් D0x7fffffffc930 හි සම්පූර්ණ දත්ත ව්‍යුහයේ සිට 0x7fffffffc940 හි ඇති ඕෆ්සෙට් එක නිවැරදිව ගණනය කර B2ඇත. 0x7fffffffc930 සහ 0x7fffffffc940 අතර ඇති දේ B1දත්ත සහ vtable විය හැකි බව අපි අනුමාන කරමු .

පසුව, පහත් කොට ඇති කොටස් වල, අවලංගු ඒවා අසමත් වන්නේ කෙසේද සහ ඇයි යන්න තේරුම් ගැනීම දැන් පහසුය:

  • static_cast<D*>(b2s[0]) 0x7fffffffc910: සම්පාදකයා ටයිම් බයිට් 0x10 කින් ඉහළට ගොස් උත්සාහ කර බැලීමට උත්සාහ B2කරයිD

    නමුත් නිසා b2s[0] එය නොවූD , එය දැන් නිර්වචනය නොකළ මතක කලාපයකට යොමු කරයි.

    විසුරුවා හැරීම:

    49          dp = static_cast<D*>(b2s[0]);
       0x0000000000000fc8 <+414>:   48 8b 45 d0     mov    -0x30(%rbp),%rax
       0x0000000000000fcc <+418>:   48 85 c0        test   %rax,%rax
       0x0000000000000fcf <+421>:   74 0a   je     0xfdb <main()+433>
       0x0000000000000fd1 <+423>:   48 8b 45 d0     mov    -0x30(%rbp),%rax
       0x0000000000000fd5 <+427>:   48 83 e8 10     sub    $0x10,%rax
       0x0000000000000fd9 <+431>:   eb 05   jmp    0xfe0 <main()+438>
       0x0000000000000fdb <+433>:   b8 00 00 00 00  mov    $0x0,%eax
       0x0000000000000fe0 <+438>:   48 89 45 98     mov    %rax,-0x68(%rbp)

    එබැවින් GCC විසින් කරන බව අපට පෙනේ:

    • දර්ශකය NULL දැයි පරීක්ෂා කරන්න, ඔව් නම් NULL ආපසු එවන්න
    • එසේ නොමැති නම්, Dනොපවතින ස්ථානයට ළඟා වීමට 0x10 එයින් අඩු කරන්න
  • dynamic_cast<D*>(b2s[0]) 0: C ++ ඇත්ත වශයෙන්ම වාත්තු අවලංගු බව සොයාගෙන නැවත ලබා දෙන ලදි nullptr !

    සම්පාදනය කරන වේලාවේදී මෙය කළ හැකි ක්‍රමයක් නොමැති අතර, එය විසුරුවා හැරීමෙන් අපි තහවුරු කරමු:

    59          dp = dynamic_cast<D*>(b2s[0]);
       0x00000000000010ec <+706>:   48 8b 45 d0     mov    -0x30(%rbp),%rax
       0x00000000000010f0 <+710>:   48 85 c0        test   %rax,%rax
       0x00000000000010f3 <+713>:   74 1d   je     0x1112 <main()+744>
       0x00000000000010f5 <+715>:   b9 10 00 00 00  mov    $0x10,%ecx
       0x00000000000010fa <+720>:   48 8d 15 f7 0b 20 00    lea    0x200bf7(%rip),%rdx        # 0x201cf8 <_ZTI1D>
       0x0000000000001101 <+727>:   48 8d 35 28 0c 20 00    lea    0x200c28(%rip),%rsi        # 0x201d30 <_ZTI2B2>
       0x0000000000001108 <+734>:   48 89 c7        mov    %rax,%rdi
       0x000000000000110b <+737>:   e8 c0 fb ff ff  callq  0xcd0 <__dynamic_cast@plt>
       0x0000000000001110 <+742>:   eb 05   jmp    0x1117 <main()+749>
       0x0000000000001112 <+744>:   b8 00 00 00 00  mov    $0x0,%eax
       0x0000000000001117 <+749>:   48 89 45 98     mov    %rax,-0x68(%rbp)

    පළමුව NULL චෙක්පතක් ඇති අතර, අයින්පුට් NULL නම් එය NULL ලබා දෙයි.

    එසේ නොමැති නම්, එය RDX, RSI සහ RDI සහ ඇමතුම් වල යම් තර්ක විතර්ක කරයි __dynamic_cast.

    මෙය තවදුරටත් විශ්ලේෂණය කිරීමට මට ඉවසීමක් නැත, නමුත් අනෙක් අය පැවසූ පරිදි, මෙය ක්‍රියාත්මක වීමට ඇති එකම ක්‍රමය __dynamic_castපන්ති ධූරාවලිය නියෝජනය කරන අතිරේක RTTI මතකයේ දත්ත ව්‍යුහයන් වෙත ප්‍රවේශ වීමයි.

    එම නිසා එය B2එම වගුව සඳහා වන ප්‍රවේශයෙන් ආරම්භ විය යුතු අතර, ඒ සඳහා වන විචල්‍යතාවය සොයා ගන්නා තෙක් මෙම පන්ති ධූරාවලියෙහි ගමන් කරන්නD සිට typecast b2s[0].

    නැවත අර්ථ නිරූපණය කිරීම මිල අධික විය හැක්කේ මේ නිසා ය! මෙතන ඇති පරිවර්තනය එක් නෞකාවක් ලප එහිදී උදාහරණයක් dynamic_castවෙත static_castසංකීර්ණ ව්යාපෘතිය 33% කින් ධාවන අඩු! .

  • reinterpret_cast<D*>(b2s[1]) 0x7fffffffc940මේ තැනැත්තා අපව අන්ධ ලෙස විශ්වාස කරයි: අපි කිව්වේ Dලිපිනයක් ඇති බවයිb2s[1] , සම්පාදකයා ඕෆ්සෙට් ගණනය කිරීම් නොකරන බවත්ය.

    නමුත් මෙය වැරදියි, D ඇත්ත වශයෙන්ම 0x7fffffffc930 හි ඇති නිසා, 0x7fffffffc940 හි ඇති දෙය D තුළ ඇති B2 වැනි ව්‍යුහයයි! එබැවින් කුණු කූඩයට ප්‍රවේශ වේ.

    -O0වටිනාකම වටා ගමන් කරන බිහිසුණු එකලස් කිරීමෙන් අපට මෙය සනාථ කළ හැකිය :

    70          dp = reinterpret_cast<D*>(b2s[1]);
       0x00000000000011fa <+976>:   48 8b 45 d8     mov    -0x28(%rbp),%rax
       0x00000000000011fe <+980>:   48 89 45 98     mov    %rax,-0x68(%rbp)

අදාළ ප්‍රශ්න:

උබුන්ටු 18.04 amd64, GCC 7.4.0 හි පරීක්ෂා කරන ලදී.

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.