c++ - أين يتم تخزين مؤشر "هذا" في ذاكرة الكمبيوتر؟



this-pointer (4)

أين يوجد مؤشر "هذا" المخزن في الذاكرة بالضبط؟ هل يتم تخصيصها في بنية تخزين العناصر أو في الكومة أو في جزء البيانات؟

#include <iostream>
using namespace std;

class ClassA
{
    int a, b;

    public:
        void add()
        {
            a = 10;
            b = 20;
            cout << a << b << endl;
        }
};

int main()
{
    ClassA obj;
    obj.add();
    return 0;
}

في الكود أعلاه ، أتصل بوظيفة العضو add() ويتم تمرير كائن المستقبل ضمنيًا كمؤشر 'this' هذا. أين يتم تخزينها في الذاكرة؟

https://ffff65535.com


أسهل طريقة هي أن تفكر في this على أنه حجة إضافية مخفية يتم تمريرها دائمًا بشكل تلقائي.

إذن ، طريقة خيالية مثل:

size_t String::length(void) const
{
  return strlen(m_string);
}

هو في الواقع أكثر مثل هذا تحت غطاء محرك السيارة:

size_t String__length(const String *this)
{
  return strlen(this->m_string);
}

ومكالمة مثل:

{
  String example("hello");
  cout << example.length();
}

يصبح شيء من هذا القبيل:

cout << String__length(&example);

لاحظ أن التحويل أعلاه مبسّط ، على أمل أن أوضح وجهة نظري قليلاً. لا حاجة لملء التعليقات مع "whaaa ، أين هو تنظيم للحمل فوق طاقتها ، هاه؟" - نوع الاعتراض ، من فضلك. :)

يحول هذا السؤال إلى "أين يتم تخزين الحجج؟" ، والجواب بالطبع "يعتمد ذلك". :)

وغالبًا ما يكون هذا على المكدس ، ولكن يمكن أن يكون في السجلات أيضًا ، أو أي آلية أخرى يعتبرها المحول البرمجي جيدة للهندسة المستهدفة.


لقد قامت الإجابات الأخرى بعمل جيد جداً يشرح كيف يقوم المترجم النموذجي بتنفيذ this (بتمريره كمعلمة أولية ضمنية للدالة).

أعتقد أنه من المفيد أيضًا معرفة ما تقوله مواصفات ISO C ++ بوضوح حول هذا الأمر. وفقًا لمواصفات C ++ 03 ISO ، §9.3.2 / 1:

في النص الأساسي لدالة عضو nonstatic (9.3) ، الكلمة الأساسية this عبارة عن تعبير غير laluue له قيمة عنوان الكائن الذي يتم استدعاء الدالة.

من المهم ملاحظة أن this ليس متغيراً - إنه تعبير ، بنفس الطريقة التي يكون فيها التعبير 1 + 2 * 3 تعبيرًا. يُسمح بتخزين قيمة هذا التعبير في أي مكان تقريبًا. قد يضع المحول البرمجي على المكدس ويقوم بتمريره كمعلمة ضمنية لدالة ما ، أو قد يضعه في سجل ، ومن الممكن تصوره وضعه في كومة الذاكرة المؤقتة أو في مقطع البيانات. مواصفات C ++ يعطي عمدا التنفيذ بعض المرونة هنا.

أعتقد أن إجابة "محامي اللغة" هي "هذا محدد تمامًا للتطبيق ، وعلاوة على ذلك ، this ليس تقنيًا مؤشرًا ، ولكنه تعبير يتم تقييمه إلى مؤشر".

أتمنى أن يساعدك هذا!


يتم تمرير this عادة كوسيطة مخفية من الأسلوب (الاختلاف الوحيد عبر مختلف الاستدعاءات هو كيفية ).

إذا كنت تتصل:

myClass.Method(1, 2, 3);

ينشئ مترجم التعليمة البرمجية التالية:

Method(&myClass, 1, 2, 3);

حيث المعلمة الأولى بالفعل مؤشر this .

دعنا نتحقق من الشفرة التالية:

class MyClass
{
private:
    int a;

public:
    void __stdcall Method(int i)
    {
        a = i;
    }
};

int main(int argc, char *argv[]) 
{
    MyClass myClass;
    myClass.Method(5);

    return 0;
}

باستخدام __stdcall أجبرت المحول البرمجي لتمرير كافة المعلمات من خلال المكدس. إذا قمت بعد ذلك بتشغيل مصحح الأخطاء وفحص رمز التجميع ، فستجد شيئًا مثل ما يلي:

     myClass.Method(5);
00AA31BE  push        5  
00AA31C0  lea         eax,[myClass]  
00AA31C3  push        eax  
00AA31C4  call        MyClass::Method (0AA1447h)  

كما ترى ، يتم تمرير المعلمة من الأسلوب من خلال المكدس ، ثم يتم تحميل عنوان myClass لتسجيل eax ودفعها مرة أخرى على المكدس. بمعنى آخر ، يتم التعامل مع this كمعامل منتظم لهذه الطريقة.


this ليس مخزنا في مكان محدد جيدا! يتم تخزين الكائن الذي يشير إليه في مكان ما ، ويحتوي على عنوان محدد جيدًا ، ولكن لا يحتوي العنوان نفسه على عنوان منزل محدد. يتم توصيلها في البرنامج. ليس هذا فقط ، ولكن يمكن أن يكون هناك العديد من نسخ هذا المؤشر.

في دالة init التالية ، يقوم الكائن بتسجيل نفسه لتلقي الأحداث و callbacks المؤقت (باستخدام كائنات مصدر الحدث الخيالي). بعد التسجيل ، هناك نسختان إضافيتان من this :

void foo_listener::init()
{
   g_usb_events.register(this); // register to receive USB events
   g_timer.register(this, 5);   // register for a 5 second timer
}

أنا سلسلة تنشيط وظيفة ، سيكون هناك أيضا نسخ متعددة من هذا المؤشر. لنفترض أن لدينا كائنًا obj وأن نطلق عليه وظيفة foo . تستدعي هذه الوظيفة وظيفة bar الكائن نفسه ، ويطلب bar وظيفة أخرى تسمى update . يحتوي كل مستوى تنشيط دالة على this المؤشر. يتم تخزينها في سجل جهاز ، أو في موقع ذاكرة في إطار الرصة الخاصة بتنشيط الوظيفة.





this-pointer