چهارشنبه، آذر ۱۱، ۱۳۸۸

کپی نکن

امروز که داشتم یه برنامه‌ی ساده رو به ++C می‌نوشتم – آمم… خوب در واقع داشتم یه برنامه‌ی از پیش نوشته شده رو بازنویسی می‌کردم(!)، خواستم یه چیزی رو آزمایش کنم.

کدی که نوشته شده بود، از پارامترهای ارجاعی استفاده کرده بود همه جا. مثلا به شکل پایین:

   1:  Test& operator + (Test const& t)
   2:  {
   3:      Test *res = new Test(t);
   4:      res.some_data += some_data;
   5:  
   6:      return *res;
   7:  }

خوبه، نه؟ دقیق، درست، تضمینی، همیشه کار می‌کنه، کپی نمی‌شه چیزی، از نو ساخته نمی‌شه چیزی، همینی که هست فقط.

حالا فکر کنید، کد رو اینجوری می‌نوشتیم:

   1:  Test operator + (Test t)
   2:  {
   3:      t.some_data += some_data;
   4:      
   5:      return t;
   6:  }
خیلی خوب می‌شدا! چه کد کوتاه‌تر و تمیزتری بود اینجوری. اگه و فقط اگه می‌تونستیم نگران کپی‌شدن‌های اضافی نباشیم. همه‌ی پارامترها و مقدار بازگشتی رو by-value رد می‌کردیم.

جدیدا متوجه شده‌م که گویا می‌شه کمی از این نگرانی‌ها کم کرد (البته فقط کمی.)؛ خصوصا اگه کامپایلر مورد استفاده از استاندارد جدید C++0x پیروی کنه.

Rvalueها

در این استاندارد مفهوم Rvalue ها هم در کنار Lvalue ها اضافه شده. Rvalueها عبارت‌های هستن که اشیاء موقتی و بدون نام می‌سازن. به این خاطر هم بهشون Rvalue گفته می‌شه که این عبارت‌ها می‌تونن فقط در سمت راست عمل انتساب قرار بگیرن.

این اشیا بدون نام هستند پس نمی‌شه بیشتر از یک بار ازشون استفاده کرد. همین‌طور موقتی هستند و بعد از محاسبه‌ی کامل عبارت، نابود می‌شن.

این دو خصوصیت Rvalueها خوبی فوق‌العاده‌ای داره: اگه بدونید که دارید از یک Rvalue کپی می‌کنید، … خوب. می‌تونید کپی نکنید! یه بار که بیشتر استفاده نمی‌شه ازش. به جای کپی کردن، می‌تونین بدزدینش!

منظور از دزدیدن Rvalue اینه که به جای این که یه کپی پرهزینه و سنگین انجام بشه، می‌تونیم یواشکی از خود Rvalue استفاده کنیم. برای مثال اگه یه Rvalue به عنوان پارامتر by-value به یه تابع رد می‌شه، می‌شه به جای کپی کردن Rvalue خود شیء رو به تابع رد کرد. اگه کامپایلر این کارو برای ما انجام بده، می‌تونیم یه call-by-valueی سبک و بی‌دردسر داشته باشیم.

اگه من بنویسم C = A + B که هر سه از نوع کلاس Test هستن که توی مثال بالا استفاده شد، حاصل عبارت A + B که به عنوان پارامتر به عملگر انتساب رد می‌شه، یک Rvalue هست. پس می‌تونم با خیال راحت به صورت by-value ردش کنم و نگران کپی شدنش نباشم.

حالا فرض کنیم کامپایلر ما این ویژگی رو نداشته باشه و همیشه کپی کنه. در این صورت هم by-value رد کردن پارامترها به مثلا تابعی که من بالا نوشتم تفاوتی ایجاد نمی‌کنه. چون عملا به جای این که من ارجاعی رد کنم و بعد خودم دستی کپی کنم، می‌تونم اجازه بدم کامپایلر عمل کپی رو برام انجام بده و من از پارامتر کپی شده استفاده کنم.

به هر حال زیاد قصد نداشتم از Rvalueها یا استاندارد جدید بنویسم. برای اطلاعات بسیار بسیار کامل cpp-next.com رو ببینید. خصوصا اولین پست این وب‌سایت که در همین مورده و کامنت‌هایی که بعضا ارزششون در حد خود پست‌هاست.

آزمایشی که انجام دادم، برای فهم همین مسئله بود. توی پست بعدی خلاصه می‌نویسمش.

هیچ نظری موجود نیست: