c++ - রজন - প্রোগ্রামিং সি




যখন অপারেটর ও ওভারলোড করা হয় তখন কীভাবে আমি একটি বস্তুর ঠিকানাটি বিশ্বাসযোগ্যভাবে পেতে পারি? (4)

আমি একটি বাস্তবায়ন দেখেছি এটি কাজ করে:

char* start = &reinterpret_cast<char&>(clyde);
ghost* pointer_to_clyde = reinterpret_cast<ghost*>(start);

আমাকে জিজ্ঞেস করো না এইটা কেমন!

নিম্নলিখিত প্রোগ্রাম বিবেচনা করুন:

struct ghost
{
    // ghosts like to pretend that they don't exist
    ghost* operator&() const volatile { return 0; }
};

int main()
{
    ghost clyde;
    ghost* clydes_address = &clyde; // darn; that's not clyde's address :'( 
}

আমি কিভাবে clyde এর ঠিকানা পেতে পারি?

আমি এমন একটি সমাধান খুঁজছি যা সব ধরণের বস্তুর জন্য সমানভাবে ভালভাবে কাজ করবে। একটি সি ++ 03 সমাধান সুন্দর হবে, তবে আমি সি ++ 11 সমাধানগুলিতেও আগ্রহী। যদি সম্ভব হয়, চলুন কোন বাস্তবায়ন-নির্দিষ্ট আচরণ এড়াতে।

আমি সি ++ 11 এর std::addressof ফাংশন টেমপ্লেট সম্পর্কে সচেতন, তবে এখানে এটি ব্যবহার করতে আগ্রহী নই: আমি বুঝতে চাই যে কিভাবে স্ট্যান্ডার্ড লাইব্রেরী প্রয়োগকারী এই ফাংশন টেমপ্লেটটি বাস্তবায়ন করতে পারে।


মূলত, আপনি বস্তুর একটি রেফারেন্স-টু-গৃহস্থালি হিসাবে পুনরায় ব্যাখ্যা করতে পারেন, এটির ঠিকানাটি গ্রহণ করুন (ওভারলোড কল করবেন না) এবং পয়েন্টারটিকে আপনার টাইপের পয়েন্টারটিতে ফিরিয়ে দিন।

Boost.AddressOf কোড ঠিক যে, শুধুমাত্র volatile এবং const যোগ্যতা অতিরিক্ত যত্ন নেওয়া।


boost::addressof এবং এর প্রয়োগকরণের উপর নজর রাখুন।


হালনাগাদ: সি ++ 11 এ, কেউ boost::addressof পরিবর্তে std::addressof ব্যবহার করতে পারে।

আসুন প্রথমে বুস্ট থেকে কোড অনুলিপি করি, বিটগুলির চারপাশে কম্পাইলার কাজটি বিয়োগ করে দিন:

template<class T>
struct addr_impl_ref
{
  T & v_;

  inline addr_impl_ref( T & v ): v_( v ) {}
  inline operator T& () const { return v_; }

private:
  addr_impl_ref & operator=(const addr_impl_ref &);
};

template<class T>
struct addressof_impl
{
  static inline T * f( T & v, long ) {
    return reinterpret_cast<T*>(
        &const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
  }

  static inline T * f( T * v, int ) { return v; }
};

template<class T>
T * addressof( T & v ) {
  return addressof_impl<T>::f( addr_impl_ref<T>( v ), 0 );
}

আমরা ফাংশন একটি রেফারেন্স পাস হলে কি হবে?

দ্রষ্টব্য: addressof একটি পয়েন্টার সাথে ফাংশন ব্যবহার করা যাবে না

C ++ যদি void func(); ঘোষণা করা হয়, তারপর func একটি ফাংশন একটি রেফারেন্স কোন যুক্তি গ্রহণ এবং কোন ফলাফল ফিরে। একটি ফাংশনের এই রেফারেন্সটিকে তিনটি কার্যকরী রূপে রূপান্তরিত করা যেতে পারে - @ কনস্টান্টিন থেকে: 13.3.3.2 অনুযায়ী উভয় T & T * ফাংশনগুলির জন্য পার্থক্যযোগ্য। প্রথমটি একটি পরিচয় রূপান্তর এবং দ্বিতীয়টি হল ফাংশন-টু-পয়েন্টার রূপান্তর উভয় "সঠিক ম্যাচ" র্যাঙ্ক (13.3.3.1.1 টেবিল 9)।

ফাংশনটির রেফারেন্স addr_impl_ref মাধ্যমে পাস করে, f এর পছন্দের জন্য ওভারলোড রেজোলিউশনে একটি অস্পষ্টতা রয়েছে, যা addr_impl_ref যুক্তি 0 জন্য সমাধান করা হয়, এটি একটি int প্রথম এবং এটি একটি long (ইন্টিগ্রাল রূপান্তর) উন্নীত করা যেতে পারে।

সুতরাং আমরা কেবল পয়েন্টার ফেরত।

একটি রূপান্তর অপারেটর সঙ্গে একটি টাইপ পাস হলে কি হবে?

যদি রূপান্তর অপারেটরটি একটি T* তবে আমাদের একটি অস্পষ্টতা রয়েছে: f(T&,long) জন্য দ্বিতীয় আর্গুমেন্টের জন্য ইন্টিগ্রেল প্রোমোশনের প্রয়োজন হয় যখন f(T*,int) জন্য রূপান্তর অপারেটরকে প্রথমে বলা হয় (ধন্যবাদ @litb)

সেটি যখন addr_impl_ref kicks in। C ++ স্ট্যান্ডার্ড ম্যান্ডেটগুলি যে একটি রূপান্তর ক্রমটি সর্বাধিক এক ব্যবহারকারী-সংজ্ঞায়িত রূপান্তর থাকতে পারে। addr_impl_ref এ টাইপ মোড়ানো এবং ইতিমধ্যে একটি রূপান্তর ক্রম ব্যবহারের জন্য জোর করে, আমরা টাইপ সঙ্গে যে কোন রূপান্তর অপারেটর "নিষ্ক্রিয়"।

এভাবে f(T&,long) ওভারলোড নির্বাচন করা হয় (এবং ইন্টিগ্রাল প্রমোশন সঞ্চালিত হয়)।

অন্য কোন ধরনের জন্য কি হবে?

এভাবে f(T&,long) ওভারলোড নির্বাচন করা হয়, কারণ টাইপ T* প্যারামিটারের সাথে মেলে না।

দ্রষ্টব্য: Borland সামঞ্জস্য সম্পর্কিত ফাইলের মন্তব্য থেকে, অ্যারে পয়েন্টার ক্ষয় না, কিন্তু রেফারেন্স দ্বারা গৃহীত হয়।

এই overload কি ঘটবে?

আমরা অপারেটিং প্রয়োগকারী এবং টাইপ এড়াতে চাই, কারণ এটি ওভারলোড করা হতে পারে।

স্ট্যান্ডার্ডটি গ্যারান্টি দেয় যে reinterpret_cast এই কাজের জন্য ব্যবহার করা যেতে পারে (@ ম্যাট্তো ইতালিয়ার উত্তরটি দেখুন: 5.2.10 / 10)।

const_cast সতর্কবার্তা এড়াতে (এবং সঠিকভাবে একটি const_cast ব্যবহার করে তাদের অপসারণ করতে) const_cast এবং volatile কোয়ালিফায়ারগুলির সাথে কিছু niceties যোগ করে।

  • কাস্টম T& char const volatile&
  • const এবং volatile স্ট্রিপ
  • ঠিকানা গ্রহণ করতে অপারেটর প্রয়োগ করুন
  • একটি T* ফিরে ফিরে T*

const / volatile juggling কালো ম্যাজিকের একটি বিট, তবে এটি কাজটি সহজ করে তোলে (বরং 4 ওভারলোড সরবরাহ করার চেয়ে)। উল্লেখ্য যে T অযোগ্য, যদি আমরা একটি ghost const& পাস করি, তাহলে T* ghost const* , এইভাবে কোয়ালিফায়ারগুলি সত্যিই হারিয়ে যায় নি।

সম্পাদনা করুন: পয়েন্টার ওভারলোড পয়েন্টারের জন্য ফাংশন ব্যবহার করা হয়, আমি কিছুটা উপরে ব্যাখ্যা সংশোধন। যদিও এখনও এটা প্রয়োজন কেন আমি বুঝতে পারছি না।

নিম্নলিখিত ideone আউটপুট এই আপ, কিছুটা পরিমাণ।







memory-address