স্ট্যাটিক_কাস্ট, ডায়নামিক_কাস্ট, কনস্ট_কাস্ট এবং পুনরায় ব্যাখ্যা_কাস্ট কখন ব্যবহার করা উচিত?


2489

এর সঠিক ব্যবহারগুলি কী:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • সি স্টাইলের castালাই (type)value
  • ফাংশন-স্টাইলের castালাই type(value)

কোনটি নির্দিষ্ট ক্ষেত্রে কোনটি ব্যবহার করবেন তা কীভাবে সিদ্ধান্ত নেওয়া যায়?



3
বিভিন্ন ধরণের কাস্ট ব্যবহারের কয়েকটি কার্যকর কংক্রিট উদাহরণের জন্য, আপনি এই অন্যান্য বিষয়ে একই প্রশ্নের প্রথম উত্তরটি পরীক্ষা করতে পারেন ।
টিমনিকি

2
আপনি উপরে আপনার প্রশ্নের জন্য সত্যিই ভাল উত্তর পেতে পারেন। তবে আমি এখানে আরও একটি বিষয় রাখতে চাই, @ ই। জেমস "এই নতুন সি ++ কাস্ট অপারেটররা কিছুই করতে পারে না এবং সি স্টাইলের কাস্ট করতে পারে না better আরও ভাল কোড পাঠযোগ্যতার জন্য এগুলি আরও কম সংযোজন করা হয়েছে।"
ব্রেকব্যাডএসপি

@ ব্র্যাকব্যাডএসপি নতুন কাস্টগুলি কেবল আরও ভাল কোড পাঠযোগ্যতার জন্য নয় । বিপজ্জনক কাজগুলি করা যেমন তাদের মানগুলির পরিবর্তে কনস্টকে দূরে ফেলে দেওয়া বা পয়েন্টারগুলি ingালাই করা শক্ত করার জন্য তারা সেখানে রয়েছে। স্ট্যাটিক_কাস্টে এসি স্টাইলের কাস্টের চেয়ে বিপজ্জনক কিছু করার সম্ভাবনা কম রয়েছে!
চৌদ্দটি দুই

@ ফুর্তি টু সম্মত হয়েছেন
ব্রেকব্যাডএসপি

উত্তর:


2569

static_castআপনার প্রথম ব্যবহারের চেষ্টা করা উচিত cast এটা তোলে (যেমন ধরনের মধ্যে অন্তর্নিহিত ধর্মান্তর ভালো জিনিস আছে intথেকে float, অথবা পয়েন্টার void*), এবং এটি স্পষ্ট রূপান্তর ফাংশন (অথবা অন্তর্নিহিত বেশী) কল করতে পারেন। অনেক ক্ষেত্রে সুস্পষ্টভাবে বক্তব্য দেওয়া static_castপ্রয়োজন হয় না, তবে এটি লক্ষ করা গুরুত্বপূর্ণ যে T(something)বাক্য গঠনটি সমতুল্য (T)somethingএবং এড়ানো উচিত (এরপরে আরও)। এ T(something, something_else)তবে নিরাপদ এবং কনস্ট্রাক্টরকে কল করার গ্যারান্টিযুক্ত।

static_castউত্তরাধিকারের শ্রেণিবিন্যাসের মাধ্যমেও নিক্ষিপ্ত হতে পারে। উপরের দিকে (বেস শ্রেণীর দিকে) কাস্ট করার সময় এটি অপ্রয়োজনীয়, তবে নীচের দিকে কাস্টিং করার সময় এটি যতক্ষণ না virtualউত্তরাধিকারের মধ্যে দিয়ে যায় ততক্ষণ এটি ব্যবহার করা যেতে পারে । এটি যাচাই করে না, তবে এটি static_castকোনও ধরণের শ্রেণিবদ্ধতাকে নিখুঁতভাবে নিচে আটকানো আচরণ যা আসলে বস্তুর ধরণ নয়।


const_castconstএকটি পরিবর্তনশীল অপসারণ বা যুক্ত করতে ব্যবহার করা যেতে পারে ; অন্য কোনও সি ++ কাস্ট এটি মুছে ফেলতে সক্ষম নয় (এমনকি নয় reinterpret_cast)। এটি লক্ষ্য করা গুরুত্বপূর্ণ যে পূর্বের constমানটি সংশোধন করা কেবলমাত্র মূল ভেরিয়েবলের ক্ষেত্রেই অপরিজ্ঞাত const; আপনি যদি এটির constসাথে ঘোষিত হয়নি এমন কোনও রেফারেন্স বন্ধ করতে ব্যবহার করেন তবে constএটি নিরাপদ। constউদাহরণস্বরূপ, ভিত্তিতে সদস্য ফাংশনগুলি ওভারলোড করার সময় এটি কার্যকর হতে পারে । এটি constকোনও অবজেক্টে যোগ করার জন্য যেমন কোনও সদস্য ফাংশন ওভারলোডকে কল করতেও ব্যবহার করা যেতে পারে ।

const_castএটি একইভাবে কাজ করে volatile, যদিও এটি কম সাধারণ।


dynamic_castপলিমারফিজম পরিচালনা করার জন্য একচেটিয়াভাবে ব্যবহৃত হয়। আপনি কোনও পলিমারফিক ধরণের কোনও অন্য শ্রেণীর ধরণের কাছে একটি পয়েন্টার বা রেফারেন্স নিক্ষেপ করতে পারেন (একটি পলিমারফিক ধরণের কমপক্ষে একটি ভার্চুয়াল ফাংশন রয়েছে, ঘোষিত বা উত্তরাধিকারসূত্রে প্রাপ্ত)। আপনি এটি কেবল নীচের দিকে castালাইয়ের চেয়ে আরও বেশি কিছুতে ব্যবহার করতে পারেন - আপনি পাশাপাশি বা অন্য কোনও চেইনও কাস্ট করতে পারেন। dynamic_castপছন্দসই বস্তুর খুঁজে বার করা এবং তা ফেরত সম্ভব হলে হবে না। যদি এটি না পারে তবে এটি nullptrকোনও পয়েন্টারের ক্ষেত্রে ফিরে আসবে , বা std::bad_castকোনও রেফারেন্সের ক্ষেত্রে নিক্ষেপ করবে।

dynamic_castযদিও কিছু সীমাবদ্ধতা রয়েছে। উত্তরাধিকারের শ্রেণিবিন্যাসে (তথাকথিত 'ভয়ঙ্কর হীরা') একই ধরণের একাধিক অবজেক্ট রয়েছে এবং আপনি virtualউত্তরাধিকার ব্যবহার করছেন না তবে এটি কাজ করে না । এটি কেবল সর্বজনীন উত্তরাধিকারের মধ্য দিয়ে যেতে পারে - এটি সর্বদা ভ্রমণ protectedবা privateউত্তরাধিকারের পথে ভ্রমণ করতে ব্যর্থ হবে । এটি খুব কমই একটি সমস্যা, যদিও উত্তরাধিকারের এই ধরণেরগুলি বিরল।


reinterpret_castএটি সবচেয়ে বিপজ্জনক castালাই এবং এটি খুব অল্প পরিমাণে ব্যবহার করা উচিত। এটি এক প্রকারকে সরাসরি অন্যটিতে রূপান্তরিত করে - যেমন একটি পয়েন্টার থেকে অন্য পয়েন্টারে মান ingালাই করা বা একটি পয়েন্টারটিকে একটি intবা অন্য সমস্ত বাজে জিনিসগুলিতে সংরক্ষণ করা। মূলত শুধু তোমার সাথে পেতে গ্যারান্টি reinterpret_castযে স্বাভাবিকভাবে যদি আপনি আসল ধরনের ফলাফলের পিছনে ফেলে, আপনি সঠিক একই মান পাবেন (কিন্তু না যদি অন্তর্বর্তী টাইপ মূল টাইপ চেয়ে ছোট)। এমন অনেকগুলি রূপান্তর রয়েছে যা reinterpret_castনাও করতে পারে। এটি প্রাথমিকভাবে বিশেষত অদ্ভুত রূপান্তর এবং বিট ম্যানিপুলেশনের জন্য ব্যবহৃত হয়, যেমন কোনও কাঁচা ডেটা স্ট্রিমকে আসল ডেটাতে পরিণত করা, বা পয়েন্টারের নীচে বিভক্ত ডেটাতে ডেটা সংরক্ষণ করা।


সি স্টাইলের castালাই এবং ফাংশন-স্টাইলের cast ালাই যথাক্রমে ব্যবহার করে (type)objectবা type(object)যথাযথভাবে সমান হয় cas এগুলি নিম্নলিখিতটির প্রথম হিসাবে সংজ্ঞাযুক্ত যা সফল হয়:

  • const_cast
  • static_cast (যদিও অ্যাক্সেস বিধিনিষেধ উপেক্ষা করে)
  • static_cast (উপরে দেখুন), তারপর const_cast
  • reinterpret_cast
  • reinterpret_castতাহলে const_cast

সুতরাং এটি কিছু ক্ষেত্রে অন্যান্য ক্যাসেটের প্রতিস্থাপন হিসাবে ব্যবহার করা যেতে পারে তবে এটি একটিতে রূপান্তরিত করার দক্ষতার কারণে অত্যন্ত বিপজ্জনক হতে পারে reinterpret_cast, এবং স্পষ্টত কাস্টিংয়ের প্রয়োজন পরে যখন অগ্রাধিকার দেওয়া উচিত তবে আপনি static_castসফল হন বা reinterpret_castব্যর্থ হবেন যদি না । তারপরেও দীর্ঘতর, আরও স্পষ্ট বিকল্প বিবেচনা করুন।

সি-স্টাইলের কাস্টগুলি কোনও সম্পাদন করার সময় অ্যাক্সেস নিয়ন্ত্রণকেও অগ্রাহ্য করে static_cast, যার অর্থ তাদের কাছে এমন কোনও অপারেশন করার ক্ষমতা রয়েছে যা অন্য কোনও কাস্ট করতে পারে না। এটি বেশিরভাগই একটি ক্লডজ, যদিও এবং আমার মনে সি-স্টাইলের কাস্টগুলি এড়ানোর আরও একটি কারণ।


17
ডায়নামিক_কাস্ট কেবল পলিমারফিক ধরণের জন্য। আপনি যখন কোনও উদ্ভূত শ্রেণিতে কাস্ট করছেন তখন আপনার কেবল এটি ব্যবহার করতে হবে। আপনার নির্দিষ্টভাবে গতিশীল_কাস্টের চমত্কার প্রয়োজন না হলে স্ট্যাটিক_কাস্ট অবশ্যই প্রথম বিকল্প। এটি সাধারণভাবে কিছু অলৌকিক রূপালী-বুলেট "টাইপ-চেকিং কাস্ট" নয়।
জালফ

2
দুর্দান্ত উত্তর! একটি তাত্ক্ষণিক মন্তব্য: আপনার ডারাইভড * এবং বেজ * এ কাস্ট করার ক্ষেত্রে স্থিত_কাস্টটি হায়ারার্কিটি কাস্ট করা প্রয়োজন হতে পারে, যেহেতু ডাবল পয়েন্টার / রেফারেন্সগুলি স্বয়ংক্রিয়ভাবে হায়ারার্কি আপ না করে। আমি এই মুহূর্তে এসেছি (স্পষ্টভাবে, সাধারণ নয়) পরিস্থিতি দুটি মিনিট আগে। ;-)
বার্টগোল

5
* "অন্য কোনও সি ++ castালাই অপসারণ করতে সক্ষম const(এমনকি নয় reinterpret_cast)" ... সত্যই? কি হবে reinterpret_cast<int *>(reinterpret_cast<uintptr_t>(static_cast<int const *>(0)))?
ব্যবহারকারী541686

29
আমি মনে করি উপরোক্ত একটি গুরুত্বপূর্ণ বিবরণ অনুপস্থিত হ'ল স্থির বা পুনরায় ব্যাখ্যা_কাস্টের তুলনায় ডায়নামিক_কাস্টের একটি রান-টাইম পারফরম্যান্স পেনাল্টি রয়েছে। এটি গুরুত্বপূর্ণ, যেমন রিয়েল-টাইম সফ্টওয়্যার।
jfritz42

5
reinterpret_castএপিআই এর অস্বচ্ছ ডেটা টাইপের সেট নিয়ে কাজ করার সময় প্রায়শই পছন্দের অস্ত্র হিসাবে উল্লেখ করা যেতে পারে
ক্লাস স্কেলটন

333

dynamic_castউত্তরাধিকার শ্রেণিবিন্যাসের মধ্যে পয়েন্টার / রেফারেন্স রূপান্তর করার জন্য ব্যবহার করুন ।

static_castসাধারণ ধরণের রূপান্তরগুলির জন্য ব্যবহার করুন ।

reinterpret_castবিট নিদর্শনগুলির নিম্ন-স্তরের পুনরায় ব্যাখ্যা করার জন্য ব্যবহার করুন । চরম সতর্কতার সাথে ব্যবহার করুন।

const_castফেলে দেওয়ার জন্য ব্যবহার করুন const/volatile। আপনি যদি কোনও কনস্ট-ভুল এপিআই ব্যবহার না করে থাকেন তবে এড়িয়ে চলুন।


2
গতিশীল_কাস্টের সাথে সাবধান হন। এটি আরটিটিআইয়ের উপর নির্ভর করে এবং ভাগ করা লাইব্রেরির সীমানা জুড়ে এটি প্রত্যাশার মতো কাজ করবে না। কেবলমাত্র আপনি নির্বাহযোগ্য এবং ভাগ করা লাইব্রেরি স্বাধীনভাবে তৈরি করার কারণে বিভিন্ন বিল্ডগুলিতে আরটিটিআই সিঙ্ক করার কোনও মানক উপায় নেই। কিউটি লাইব্রেরিতে এই কারণে qobject_cast <> উপস্থিত রয়েছে যা প্রকারগুলি পরীক্ষা করার জন্য কিউবজেক্ট টাইপ তথ্য ব্যবহার করে।
ব্যবহারকারী 3150128

198

(উপরে অনেক তাত্ত্বিক এবং ধারণাগত ব্যাখ্যা দেওয়া হয়েছে)

নীচে কিছু বাস্তব উদাহরণ আমি যখন ব্যবহৃত static_cast , dynamic_cast , const_cast , reinterpret_cast

(ব্যাখ্যাটি বোঝার জন্য এটিও রেফার করে: http://www.cplusplus.com/doc/tutorial/typecasting/ )

স্ট্যাটিক_কাস্ট:

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( ... )*/{
        // ...
    }
}

কনস্ট_কাস্ট:

// *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
পুনরায় সংজ্ঞা_কাস্টের শেষ ব্যবহার সম্পর্কে: এটি ব্যবহারের মতো নয় static_cast<char*>(&val)কি?
লরেঞ্জো বেলি

3
@ লোরেঞ্জোবেলি অবশ্যই না। তুমি কি চেষ্টা করেছ? পরবর্তীটি বৈধ সি ++ নয় এবং সংকলনটি অবরুদ্ধ করে। static_castকেবলমাত্র সংজ্ঞায়িত রূপান্তরগুলির সাথে, উত্তরাধিকারের দ্বারা দৃশ্যমান সম্পর্ক বা / থেকে প্রকারের মধ্যে কাজ করে void *। অন্য কিছুর জন্য, অন্যান্য ক্যাসেট রয়েছে। reinterpret castযে কোনও char *শব্দকে যে কোনও বস্তুর প্রতিনিধিত্ব পড়ার অনুমতি দেওয়া হয় - এবং কেবলমাত্র এমন একটি ক্ষেত্রে যেখানে কীওয়ার্ডটি কার্যকর হয় - প্রয়োগের কোনও জেনারেটর নয় / অবধারিত আচরণ নয়। তবে এটি 'সাধারণ' রূপান্তর হিসাবে বিবেচিত হয় না, তাই (সাধারণত) খুব রক্ষণশীলদের দ্বারা অনুমোদিত নয় static_cast
আন্ডারস্কোর_ড

2
আপনি যখন ডেটাবেসগুলির মতো সিস্টেম সফ্টওয়্যার নিয়ে কাজ করছেন তখন পুনরায় ব্যাখ্যা_কাস্ট বেশ সাধারণ। বেশিরভাগ ক্ষেত্রে আপনি নিজের পৃষ্ঠা পরিচালককে লেখেন যা পৃষ্ঠায় সঞ্চিত ডেটা টাইপ কী তা সম্পর্কে কোনও ধারণা নেই এবং কেবল একটি অকার্যকর পয়েন্টার প্রদান করে। এটি পুনরায় ব্যাখ্যা করার জন্য কাস্ট করতে উচ্চতর স্তরের অবধি এবং তারা যা খুশি তাই নির্ধারণ করে।
সোহাইব

1
কনস্টাস্ট কাস্টম উদাহরণটি অনির্ধারিত আচরণ প্রদর্শন করে। কনস্ট হিসাবে ঘোষিত একটি পরিবর্তনশীল ডি-কনড-এড হতে পারে না। যাইহোক, একটি পরিবর্তনশীল নন-কনস্ট হিসাবে ঘোষণা করা হয় যা কোনও কনস্ট্রের রেফারেন্স গ্রহণ করে কোনও ফাংশনে পাস হয়ে যায় function ফাংশনটিতে এটি ইউবি হওয়ায় ডি-কনস্ট-এড হতে পারে।
জোহান জেরেল

99

আপনি যদি অভ্যন্তরীণ কিছুটা জানেন তবে এটি সাহায্য করতে পারে ...

static_cast

  • সি ++ সংকলক ইতিমধ্যে জানে যে কীভাবে স্কেলারের ধরণের মধ্যে ফ্লোটকে ইনটে রূপান্তর করতে হয়। static_castতাদের জন্য ব্যবহার করুন।
  • আপনি যখন সংকলককে টাইপ থেকে রূপান্তর Aকরতে বলেন B, static_castকলগুলির Bকনস্ট্রাক্টরকে পরম Aহিসাবে পাস করছেন। বিকল্পভাবে, Aএকটি রূপান্তর অপারেটর (যেমন A::operator B()) থাকতে পারে could যদি Bএই জাতীয় নির্মাতা না থাকে বা Aকোনও রূপান্তর অপারেটর না থাকে তবে আপনি সংকলনের সময় ত্রুটি পান।
  • A এবং B যদি উত্তরাধিকারের শ্রেণিবিন্যাসে (বা বাতিল) থাকে তবে সর্বদা সফল A*হতে কাস্ট করুন B*অন্যথায় আপনি সংকলন ত্রুটি পান।
  • গোছা : আপনি যদি ডাইরেক্ট পয়েন্টারটিতে বেস পয়েন্টারটি কাস্ট করেন তবে সত্যিকারের অবজেক্টটি যদি সত্যই ডারেক্টেড টাইপ না হয় তবে আপনি ত্রুটি পাবেন না । আপনি খারাপ পয়েন্টার পেয়েছেন এবং খুব সম্ভবত রানটাইমের সময় একটি সেগফল্ট পাবেন। একই জন্য যায় A&থেকে B&
  • গোছা : উত্পন্ন থেকে বেসে কাস্ট বা বিপরীতে নতুন অনুলিপি তৈরি হয় ! সি # / জাভা থেকে আগত লোকদের জন্য, এটি একটি বিশাল আশ্চর্য হতে পারে কারণ ফলাফলটি মূলত ডেরাইভ থেকে তৈরি একটি কাটা অফ অবজেক্ট।

dynamic_cast

  • গতিশীল_কাস্ট কাস্ট বৈধ কিনা তা বের করার জন্য রানটাইম টাইপ তথ্য ব্যবহার করে। উদাহরণস্বরূপ, (Base*)থেকে (Derived*)ব্যর্থ হতে পারে যদি পয়েন্টার উদ্ভূত ধরনের আসলে নয়।
  • এর অর্থ, স্ট্যাটিক_কাস্টের তুলনায় ডায়নামিক_কাস্ট খুব ব্যয়বহুল!
  • এর A*জন্য B*, যদি কাস্টটি অবৈধ হয় তবে ডায়নামিক_কাস্ট নালপ্ট্র ফিরে আসবে।
  • জন্য A&করতে B&যদি ঢালাই অবৈধ তারপর dynamic_cast bad_cast ব্যতিক্রম নিক্ষেপ করা হবে।
  • অন্যান্য ক্যাসেটের মতো নয়, রানটাইম ওভারহেড রয়েছে।

const_cast

  • স্ট্যাটিক_কাস্ট কনস্ট্যান্ট করার জন্য নন-কনস্ট্যান্ট করতে পারে তবে অন্য পথে যেতে পারে না। কনস্ট_কাস্ট উভয় উপায়ে করতে পারে।
  • একটি উদাহরণ যেখানে এইটি কার্যকর হয় তা এমন কিছু ধারক দিয়ে পুনরাবৃত্তি হয় set<T>যা কেবলমাত্র তার উপাদানগুলি পরিবর্তন করে না তা নিশ্চিত করার জন্য এটির উপাদানগুলি প্রতিস্থাপন করে returns তবে যদি আপনার অভিপ্রায় অবজেক্টের নন-কী সদস্যদের পরিবর্তন করতে হয় তবে তা ঠিক হওয়া উচিত should স্থিরতা অপসারণ করতে আপনি কনস্টেইকাস্ট ব্যবহার করতে পারেন।
  • আরেকটি উদাহরণ হয় যখন আপনি বাস্তবায়ন করতে চান T& SomeClass::foo()সেইসাথে const T& SomeClass::foo() const। কোড সদৃশতা এড়ানোর জন্য, আপনি অন্য থেকে একটি ফাংশনের মান ফেরত দিতে কনস্ট_কাস্ট প্রয়োগ করতে পারেন।

reinterpret_cast

  • এটি মূলত বলেছে যে এই বাইটগুলি এই মেমরির অবস্থানটিতে নিয়ে যান এবং প্রদত্ত বস্তু হিসাবে এটি ভাবেন।
  • উদাহরণস্বরূপ, ফ্লোটের বিটগুলি দেখতে কেমন তা দেখতে আপনি 4 বাইট ফ্লোটের 4 টি বাইটে লোড করতে পারেন।
  • স্পষ্টতই, যদি টাইপটির জন্য ডেটা সঠিক না হয় তবে আপনি সেগফল্ট পেতে পারেন।
  • এই কাস্টের জন্য কোনও রানটাইম ওভারহেড নেই।

আমি রূপান্তরকারী অপারেটরের তথ্য যুক্ত করেছি, তবে আরও কয়েকটি জিনিস রয়েছে যা ঠিক করা উচিত এবং এটিকে খুব বেশি আপডেট করার ক্ষেত্রে আমি স্বাচ্ছন্দ্য বোধ করি না। আইটেমগুলি 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.হ'ল : 1. আপনি ইউবি পাবেন যা ভাগ্যবান হলে রানটাইমের সময় সেগফল্টের ফলস্বরূপ। ২. গতিশীল কাস্টগুলি ক্রস কাস্টিংয়েও ব্যবহার করা যেতে পারে। ৩. কনস্ট কাস্টের কিছু ক্ষেত্রে ইউবি হতে পারে। mutableযৌক্তিক দৃ const়তা প্রয়োগ করার জন্য ব্যবহার করা আরও ভাল পছন্দ হতে পারে।
অ্যাড্রিয়ান

1
@ অ্যাড্রিয়ান আপনি সমস্ত গণনায় সঠিক। উত্তর কমবেশি শিক্ষানবিস স্তরের লোকদের জন্য লেখা হয়েছে এবং আমি তাদের mutableক্রস কাস্টিং ইত্যাদির সাথে যে সমস্ত জটিলতা দেখা দেয় সেগুলি দিয়ে অভিভূত করতে চাইনি
শীতল শাহ

16

না এই আপনার প্রশ্নের উত্তর দিতে?

আমি কখনই ব্যবহার করিনি reinterpret_cast, এবং ভাবছি যে এটির প্রয়োজনে এমন কোনও কেস খারাপ ডিজাইনের গন্ধ নয় into আমি যে কোড বেসে কাজ করি তাতে dynamic_castপ্রচুর ব্যবহৃত হয়। পার্থক্য static_castহ'ল একটি dynamic_castরানটাইম চেক যা কোনও (নিরাপদ) বা না হতে পারে (আরও ওভারহেড) আপনি যা চান তা হতে পারে ( এমএসডিএন দেখুন )।


3
আমি এক উদ্দেশ্যে reintre ব্যাখ্যা_cast ব্যবহার করেছি - বিটগুলি একটি ডাবল থেকে বের করে দেওয়া (আমার প্ল্যাটফর্মে দীর্ঘ হিসাবে একই আকার)।
জোশুয়া

2
পুনরায় সংজ্ঞা_কাস্ট প্রয়োজন যেমন COM অবজেক্টের সাথে কাজ করার জন্য। 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এই কাঁচা তথ্যটিকে বস্তুতে পরিণত করতে ব্যবহৃত হয়।
কালিরিহানমান 0772989

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

অন্য উত্তরগুলি সি ++ কাস্টের মধ্যে সমস্ত পার্থক্য সুন্দরভাবে বর্ণনা করার সময়, আমি কেন একটি ছোট নোট যুক্ত করতে চাই যে আপনি কেন সি-স্টাইলের কাস্ট ব্যবহার করবেন না (Type) varএবং Type(var)

সি ++ নতুনদের জন্য সি স্টাইলের বর্ণগুলি দেখতে দেখতে সি ++ জ্যাকেট (স্ট্যাটিক_কাস্ট <> ()), ডায়নামিক_কাস্ট <> (), কনস্ট_কাস্ট <> (), পুনরায় ব্যাখ্যা_কাস্ট <> ()) এবং কেউ তাদের সি ++ বর্ণের চেয়ে পছন্দ করতে পারে । আসলে সি স্টাইলের 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.

ভাষায় সি ++ ক্যাস্ট যুক্ত হওয়ার মূল কারণটি হ'ল কোনও বিকাশকারীকে তার উদ্দেশ্যগুলি স্পষ্ট করার অনুমতি দেওয়া - তিনি কেন এই কাস্ট করতে চলেছেন। সি স্টাইলের ক্যাসেটগুলি ব্যবহার করে যা সি ++ এ পুরোপুরি বৈধ, আপনি আপনার কোডটি কম পঠনযোগ্য এবং বিশেষত অন্য বিকাশকারীদের যারা আপনার কোড তৈরি করেন নি তাদের পক্ষে আরও ত্রুটি প্রবণ করে তুলছেন। সুতরাং আপনার কোডটি আরও পঠনযোগ্য এবং স্পষ্ট করে তোলার জন্য আপনাকে সর্বদা সি স্টাইলের বর্ণের চেয়ে সি ++ ক্যাসেট পছন্দ করা উচিত।

এখানে বার্জন স্ট্রোস্ট্রপের (সি ++ এর লেখক) বইটি সি ++ প্রোগ্রামিং ল্যাঙ্গুয়েজ 4 র্থ সংস্করণ - পৃষ্ঠা 302 থেকে একটি সংক্ষিপ্ত উদ্ধৃতি দেওয়া হয়েছে।

নামী রূপান্তর অপারেটরদের তুলনায় এই সি স্টাইলের castালাই বিপজ্জনক, কারণ একটি বড় প্রোগ্রামে স্বরলিপিটি পাওয়া শক্ত এবং প্রোগ্রামার দ্বারা রুপান্তরিত ধরণের রূপান্তরটি স্পষ্ট নয়।


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 প্রয়োজন এবং পূর্ণসংখ্যা এবং অন্যান্য পয়েন্টার ধরনের পয়েন্টার ধরনের অনিরাপদ ধর্মান্তর না। আমরা কেবল কী করছি তা যদি জানা থাকে এবং আমরা এলিয়াসিংয়ের সমস্যাগুলি বুঝতে পারি তবেই এটি ব্যবহার করুন।

2

static_castবনাম dynamic_castবনাম reinterpret_castঅভ্যন্তরীণ একটি ডাউনকাস্ট / আপকাস্টে দেখুন

এই উত্তরে আমি এই তিনটি প্রক্রিয়াটিকে একটি কংক্রিট আপকাস্ট / ডাউনকাস্ট উদাহরণের সাথে তুলনা করতে চাই এবং বিশ্লেষণ করতে চাই যে অন্তর্নিহিত পয়েন্টার / মেমরি / অ্যাসেমব্লিকে কীভাবে তারা তুলনা করে তার একটি দৃ understanding় ধারণা দেয়।

আমি বিশ্বাস করি যে এই ক্যাসেটগুলি কীভাবে আলাদা সে সম্পর্কে এটি একটি ভাল অনুভূতি দেবে:

  • static_cast: রানটাইম এ অফসেট করে একটি ঠিকানা করে (কম রানটাইম প্রভাব) এবং কোনও সুরক্ষা চেক করে না যে ডাউনস্ট্রাকটি সঠিক কিনা।

  • dyanamic_cast: রানটাইমের সময় একই ঠিকানাটি অফসেট করে static_castতবে এটি এবং একটি ব্যয়বহুল সুরক্ষা পরীক্ষা করে দেখুন যে আরটিটিআই ব্যবহার করে একটি ডাউনকাস্ট সঠিক কিনা correct

    এই সুরক্ষা চেক আপনাকে কোনও বেইস ক্লাস পয়েন্টার রানটাইমে প্রদত্ত ধরণের কিনা তা জিজ্ঞাসা করার অনুমতি দেয় 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.wikedia.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এটি মেমরি কাঠামো যে সঙ্গে সামঞ্জস্যপূর্ণ ভিতরে রয়েছে B1এবং যে B2অভ্যন্তরীণভাবে।

অতএব আমরা সমালোচনামূলক সিদ্ধান্তে পৌঁছেছি:

একটি আপকাস্ট বা ডাউনকাস্ট কেবল পয়েন্টার মানটি সংকলন সময়ে পরিচিত একটি মান দ্বারা স্থানান্তরিত করতে হবে

এইভাবে, যখন Dবেস টাইপ অ্যারেতে পৌঁছে দেওয়া হয়, টাইপ কাস্টটি আসলে সেই অফসেট গণনা করে B2এবং মেমরির ক্ষেত্রে একেবারে বৈধের মতো দেখতে এমন কিছু নির্দেশ করে :

b2s[1] = &d;

Dপরিবর্তে এই একটির পরিবর্তে এর জন্য vtable রয়েছে B2এবং তাই সমস্ত ভার্চুয়াল কল স্বচ্ছতার সাথে কাজ করে।

এখন, আমরা শেষ পর্যন্ত টাইপ করা কাস্টিং এবং আমাদের দৃ concrete় উদাহরণের বিশ্লেষণে ফিরে যেতে পারি।

স্টাডআউট আউটপুট থেকে আমরা দেখতে পাই:

&d           0x7fffffffc930
b2s[1]       0x7fffffffc940

অতএব, static_castসেখানে সম্পন্ন Dইমপ্লিট 0x7fffffffc930 এ পূর্ণ ডেটা স্ট্রাকচার থেকে 0x7fffffffc940 এর B2মতো একটিতে অফসেটটি সঠিকভাবে গণনা করেছে did আমরা এটিও নির্ধারণ করি যে 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)

    সুতরাং আমরা দেখতে পাই যে জিসিসি তা করে:

    • পয়েন্টারটি নুল কিনা, এবং হ্যাঁ যদি নুল ফিরে আসে তা পরীক্ষা করে দেখুন
    • অন্যথায়, এটি থেকে পৌঁছানোর জন্য এটি থেকে 0x10 বিয়োগ করুন Dযা বিদ্যমান নেই
  • dynamic_cast<D*>(b2s[0]) 0: সি ++ আসলে পাওয়া গেছে যে কাস্টটি অবৈধ এবং ফিরে এসেছে 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)

    প্রথমে একটি নুল চেক আছে, এবং এটি যদি এনইউএল হয় তবে এটি নুল ফেরত দেয়।

    অন্যথায়, এটি আরডিএক্স, আরএসআই এবং আরডিআই এবং কলগুলিতে কিছু যুক্তি সেট আপ করে __dynamic_cast

    এটিকে আরও বিশ্লেষণ করার মতো ধৈর্য আমার এখন নেই, তবে অন্যরা যেমন বলেছে, এটির কাজ করার একমাত্র উপায় হ'ল __dynamic_castকিছু অতিরিক্ত আরটিটিআই-তে মেমরির ডেটা স্ট্রাকচারগুলি অ্যাক্সেস করা যা শ্রেণি শ্রেণিবিন্যাসের প্রতিনিধিত্ব করে।

    সুতরাং এটি অবশ্যই সেই B2টেবিলটির প্রবেশ থেকে শুরু হওয়া উচিত , তারপরে এই শ্রেণীর শ্রেণিবিন্যাসটি হাঁটা পর্যন্ত এটি কোনও Dটাইপকাস্টের ভিটিবেল না পাওয়া পর্যন্ত b2s[0]

    এই কারণেই পুনরায় ব্যাখ্যা কাস্ট সম্ভাব্য ব্যয়বহুল! এখানে একটি উদাহরণ যেখানে এক মাছ ধরার নৌকা প্যাচ একটি রূপান্তর dynamic_castএকটি থেকে static_castএকটি জটিল প্রকল্পে 33% দ্বারা রানটাইম লঘু!

  • reinterpret_cast<D*>(b2s[1]) 0x7fffffffc940এটি কেবল আমাদের অন্ধভাবে বিশ্বাস করে: আমরা বলেছিলাম একটি Dঠিকানা আছে b2s[1], এবং সংকলকটি অফসেট গণনা করে না।

    তবে এটি ভুল, কারণ ডি আসলে 0x7fffffffc930 এ, 0x7fffffffc940 এ যা হয় ডি এর ভিতরে বি 2-এর মতো কাঠামো! সুতরাং ট্র্যাশ অ্যাক্সেস হয়ে যায়।

    আমরা জঘন্য -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, জিসিসি 7.4.0 এ পরীক্ষিত।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.