يعتقد البعض انه لتعود بمؤشر من الداله لابد ان يتم حجز ما يشير له هذا المؤشر بالكلمه new و ذلك حتى يتم انشاء المساحه لهذا الكائن داخل الـ heap و يصبح متاحا التعامل معه بعد الإنتهاء من الداله.
ايضا كل الكتب تحذر بشده من ارجاع مرجع لكائن تم انشائه داخل داله حيث انه بعد الخروج من الداله يصبح المؤشر غير سليم و يصبح المؤشر يشير إلى garbage.
يوجد 3 انواع من الكائنات يمكن انشائهم داخل الـ C++:
النوع الأول هو automatic object و هو ما يقوم المترجم بحجز مساحه له و لكن يقوم هو بحذفه بعد ان يتم تجاوز المدى الذى تم التصريح عنه فيه.
النوع الثانى هو dynamic object و هو النوع الذى يتم حجز مساحته بإستخدام new و لا يتم تحرير هذه المساحه إلا بإستخدام delete او بإنتهاء البرنامج.
النوع الثالث هو static object و هو يتم حجز مساحه له قبل بدء البرنامج فى العمل و لا يتم حذفه إلا بإنتهاء البرنامج.
فكره هذا الموضوع هى كيفية ارجاع automatic object من الداله دون ان يتم حفه من الـ stack.
انظر هذا المثال
[color= #007f00;]#include <iostream>
[color= #0000ff;]using [color= #0000ff;]namespace std;
[color= #0000ff;]struct Point2D
[color= #000000;]{
[color= #0000ff;]float x, y;
Point2D[color= #000000;]([color= #000000;]) [color= #000000;]: x[color= #000000;]([color= #ff0000;]0[color= #000000;]), y[color= #000000;]([color= #ff0000;]0[color= #000000;]) [color= #000000;]{[color= #000000;]}
Point2D[color= #000000;]([color= #0000ff;]float _x, [color= #0000ff;]float _y[color= #000000;]) [color= #000000;]: x[color= #000000;](_x[color= #000000;]), y[color= #000000;](_y[color= #000000;]) [color= #000000;]{[color= #000000;]}
[color= #000000;]};
Point2D[color= #000000;]* tmp;
Point2D[color= #000000;]* getPoint[color= #000000;]([color= #000000;])
[color= #000000;]{ [color= #0000ff;]return [color= #000000;]&Point2D[color= #000000;]([color= #ff0000;]3.14f,[color= #ff0000;]2.71f[color= #000000;]); [color= #000000;]}
[color= #0000ff;]void PrintData[color= #000000;]([color= #000000;])
[color= #000000;]{
cout [color= #000000;]<< [color= #A31515;]"from PrintData()n";
Point2D[color= #000000;]* pt [color= #000000;]= getPoint[color= #000000;]([color= #000000;]);
cout [color= #000000;]<< [color= #A31515;]"X = " [color= #000000;]<< pt[color= #000000;]-[color= #000000;]>x [color= #000000;]<< [color= #A31515;]", Y = " [color= #000000;]<< pt[color= #000000;]-[color= #000000;]>y [color= #000000;]<< endl;
pt[color= #000000;]-[color= #000000;]>x [color= #000000;]= [color= #ff0000;]5;
pt[color= #000000;]-[color= #000000;]>y [color= #000000;]= [color= #ff0000;]7;
tmp [color= #000000;]= pt;
[color= #000000;]}
[color= #0000ff;]void main[color= #000000;]([color= #000000;])
[color= #000000;]{
PrintData[color= #000000;]([color= #000000;]);
cout [color= #000000;]<< [color= #A31515;]"from main()n";
cout [color= #000000;]<< [color= #A31515;]"X = " [color= #000000;]<< tmp[color= #000000;]-[color= #000000;]>x [color= #000000;]<< [color= #A31515;]", Y = " [color= #000000;]<< tmp[color= #000000;]-[color= #000000;]>y [color= #000000;]<< endl;
[color= #000000;]}نتيجة هذا البرنامج هى (على جهازى)
from PrintData()
X = 3.14, Y = 2.71
from main()
X = -1.07374e+008, Y = -1.07374e+008
Press any key to continue . . .
فى البدايه قمت بصنع Point2D و التى تمثل نقطه ثم بعدها قمت بإنشاء الداله التى ستعود بمؤشر لكائن من هذا النوع و هى الداله getPoint.
بعدها قمت بصنع الداله التى ستسخدم القيمه المعاده من getPoint و هى الداله PrintData و التى كل ما تفعله هى طباعة القيمه العائده من getPoint اقوم بتعديل قيم التى يشير لها المؤشر العائد من getPoint ثم اقوم بالأحتفاظ بالعنوان الموجود بهذا المؤشر حتى استخدمه لاحقا من داخل الداله main.
داخل الداله main يتم استدعاء الداله PrintData و التى بدورها تقوم بإستدعاء getPoint و بعدها تطبع القيم و تحتفظ بقيمة المؤشر داخل المتغير tmp بعدها يتم العوده للداله main مره اخرى و التى تقوم بطباعة ما يشير إليه المتغير tmp.
فى المره الأولى التى تم طباعة x و y من داخل PrintData تم طباعة قيم صحيحه اما عند طباعة القيم الموجوده بنفس المكان من الداله main ظهرت لنا garbage.
عندما تقوم بإنشاء متغير داخل scope معين يتم الإحتفاظ بهذا الكائن حتى يتم الخروج من هذا الـ scope هذه القاعدة تطبق فى جميع الحالات مع الـ automatic obhect إلا فى حالة واحده و هى مع الكلمه return حيث فعليا القيمه العائده من return هى لا تنتمى للـ scope الذى تم كتابة return فيه و إنما إلى الـ scope الذى تم استدعاء الداله التى مكتوب فيها return.
قد يقول البعض إذا من الممكن تعريف كائن داخل scope معين ثم العوده به عن طريق return؟ لا هذا لن يحدث و السبب انظر حيث تم التصريح عن هذا الكائن فإن كان امام return فهو لا ينتمى لهذه الداله و لكن للمكان الذى تم استدعاء الداله منه و إن كان داخل الداله فهو ملك للداله و سوف يتم تدميره بمجرد الخروج من الداله.
و لهذا فقد قمت بإرجاع عنوان كائن تم انشائه امام return و بالتالى هذا الكائن لا ينتمى للـ scope الخاص بالداله getPoint و إنما للداله PrintData.
لذلك عندما قمت بالتعامل مع ما يشير له هذا المؤشر من داخل الداله main كان هذا خارج مجال تعريفه لذا لم يكن موجود لإنه تم حذفه بمجرد الخروج من الداله PrintData.
اعرف ان الشرح ليس جيدا، و لكن ارجو ان تكون الفكره قد وصلت لكم.
و الله ولى التوفيق


