کنترل حافظه برنامه با Valgrind

خیلی پیش میاد برنامه‌هایی تو cpp بنویسیم که اشکال مدیریت حافظه داشته باشن. به خصوص وقتی کارای پیچیده با پویینترها می کنیم از این دست مشکلا زیاد پیش میاد. تو این شرایط نیاز به ابزاری داریم که برنامه ما رو به لحاظ مدیریت حافظه چک کنه. خوب Valgrind عزیز ما از این دست برنامه هاست.

Valgrind
برای استفاده از Valgrind کافیه که برنامه رو با سوییچ g و ترجیحا همراه با سوییچ O0 کامپایل کنید. اولی به برنامه اطلاعات دیباگ اضافه می کنه و سوییچ دوم جلوی اپتیمایز شدن برنامه رو می گیره تا شماره خطا موقع اشکال‌زدایی درست نمایش داده بشن. فرض کنید برنامه تون که به این روش کامپایل شده اسمش باشه prog. برای کنترل این برنامه کافیه اون رو با Valgrind فراخوانی کنید:
[bash]
valgrind prog
[/bash]
Valgrind خیلی شیک و مجلسی برنامه رو اجرا می کنه و هر جا ایراد حافظه بود بهمون اعلام می کنه. دو تا سوییچ خیلی کاربردیش یکی leak-check اه که خطاهای نشت حافظه رو کنترل می کنه و دیگه track-origins=yes که دقیق مشخص می کنه این خطا مال کجای برنامه اصلیه.

Valgrind ابزارای دیگه ای مثل profiling و پیدا کردن race condition ها برای برنامه سازی موازی هم داره که می شه از مستنداتش خوند.

نکته مهم: من تو این کار خاصی که رفتم سراغ Valgrind، اگر به همه warning های کامپایلر توجه کرده بودم، اساسا مشکلم به Valgrind نمی‌کشید. روشن نگه داشتن سوییچ Wall کامپایلر و توجه به پیغاماش همیشه ایده خوبیه.

یه makefile کلی برای پروژه‌های ‪C++

اگه makefile پروژه‌های ‪C++‬ رو با روش‌های معمول بنویسیم، مجبوریم که مرتب با هر بار اضافه کردن یه فایل به پروژه makefile رو هم به روز رسانی کنیم. هر بار هم که وابستگی اون فایل تغییر می‌کنه ناچاریم این کار رو دوباره انجام بدیم. دنبال راه حل این مساله بودم که با سوییچ‌های خانواده M کامپایلر گنو آشنا شدم. این سوییچ‌ها به کامپایلر می‌گن که وابستگی یه برنامه رو به فرمت makefile بیرون بکشه. اگه این وابستگی‌ها رو تو یه فایل ذخیره کنیم می‌تونیم بعدا با دستور include از اون‌ها برای معرفی وابستگی‌ها استفاده کنیم.

  • سوییچ M این وابستگی‌ها رو بیرون می‌کشه
  • سوییچ MM مثل M اما فایل‌هایی که تو دایرکتوری‌های سیستم هستن رو به عنوان وابستگی معرفی نمی‌کنه.
  • سوییچ MF خروجی رو تو یه فایل می‌ریزه
  • سوییچ MT هم target مربوط به rule رو عوض می‌کنه. به طور پیش‌فرض قاعده تولید شده به اسم فایل ورودی منهای اسم و دایرکتوری و پسونده. در حالتی که بخوایم قاعدمون اسم دیگه‌ای داشته باشه از این سوییچ استفاده می‌کنیم. مثلا اینجا اسم قاعدمون رو به اسم آبجکت فایل با دایرکتوریش تغییر دادم.

دیگه؟ با اون ‪.PHONY‬ هم به make می‌گم که قاعده‌هایی که بعدش اومده اسم فایل نیست.
این هم makefile ما:

مقایسه سرعت c با فرترن و کلمه کلیدی restrict

یکی از چیزهایی که فرترن بازها خیلی ادعاش رو می‌کنن سرعت زیاد کدهای محاسباتی‌شونه. خوب البته تو کار ما این مساله خیلی هم اهمیت داره. یه سری که با یکی از بچه‌های کامپیوتری سر این مساله بحث بود بدون تعصب ادعا می‌کرد که چند تا بنچ مارک برای محاسبات ماتریسی گرفته و تو اون‌ها فرترن سریع‌تر از C بوده. این قضیه واسه من عجیب بود. یه سرچ زدم و دیدم که بله. این قضیه تا حدودی درسته. علت هم اینه که زبون C عزیز ما به علت این که یه زبون سطح پایین محسوب می‌شه تو حلقه‌هانمی‌تونه مطمئن باشه که مقادیر متغیرها دست نخورده می‌مونه و به همین علت مرتب اون‌ها رو آپدیت می‌کنه. بزارید یه مثال بزنم.
[c]
for(int i=0;iآپدیت مهم: همین الان یه بنچ‌مارک خوب بین C و فرترن گرفتم. یه الگوریتم دقیقا به صورت یک‌سان با C و فرترن پیاده شده بود. بدون این تکنیک، سرعت کد C تقریبا نصف فرترن بود. با استفاده از این روش، زمان محاسباتی برنامه C به ۶۵٪ کد فرترن کاهش پیدا کرد. با تشکر از حبیب عبدی عزیز برای پیاده‌سازیش.

منابع: + + +

سازنده ها در c++11، قسمت سوم: مقداردهی یکسان

تو دو تا پست قبل در باره سازنده‌ها در c++11 نوشتم (اینجا و اینجا). این پست آخر از این سریه و به مقداردهی جدید اختصاص داره.

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

[cpp light=”true”]
int arr[4]={0,1,2,3};
[/cpp]

اما مقداردهی با این سبک تو استاندارد جدید:

  • آرایه‌های پویا:
    [cpp light=”true”]
    int* a = new int[3] { 1, 2, 0 };
    [/cpp]
  • سازنده‌های کلاس‌ها:
    [cpp light=”true”]
    class C
    {
    int a;
    int b;
    public:
    C(int i, int j);
    }; 

    C c {0,0}; //Equivalent to: C c(0,0);
    [/cpp]

  • مقداردهی اولیه به اعضای آرایه‌ای در سازنده:
    [cpp light=”true”]
    class X {
    int a[4];
    public:
    X() : a{1,2,3,4} {} //C++11, member array initializer
    };
    [/cpp]
  • استفاده از std::initializer_list: اگر پارامتر سازنده از نوع std::initializer_list باشه، سازنده میتونه هر چند تا پارامتر بگیره. به طور خاص این حالت برای کلاس‌هایی که به شکل ذخیر کننده عمل می‌کنند مفیده. مثلا containerهای stl:
    [cpp light=”true”]
    vector vs={ “first”, “second”, “third”};
    map singers =
    { {“Lady Gaga”, “+1 (212) 555-7890”},
    {“Beyonce Knowles”, “+1 (212) 555-0987”}};
    [/cpp]

منابع: اینجا و اینجا

سازنده ها در c++11، قسمت دوم: ارث بری و مقدار دهی اعضا

هفته قبل در مورد محول کردن سازنده های c++11 نوشتم. اینجا میخوام دو تا ویژگی جدید در رابطه با سازنده های c++11 رو معرفی کنم:

  1. به ارث بری سازنده ها: واقعا کفر آدم رو در می آورد. بعد اینکه کلاس فرزند رو به ارث می بری باید بشینی دوباره از اول سازنده هاش رو بازنویسی کنی. خوب این قضیه رو c++11 حل کرده. سینتکسش هم این شکلیه:
    [cpp]
    class BaseClass {
    public:
    BaseClass(int value);
    };

    class DerivedClass : public BaseClass {
    public:
    using BaseClass::BaseClass;
    };
    [/cpp]
    چند تا نکته اما هست که باید دقت بشه:

    • این ویژگی تمام سازنده های کلاس پایه رو با هم به ارث میبره. یعنی نمیشه از بین سازنده ها انتخاب کرد.
    • کلاس فرزند دیگه نمیتونه سازنده ای داشته باشه که امضاش با کلاس مادر یکیه. به نظر من البته این نکته خیلی محدود کنندست.
    • اگه کلاسی همزمان دو تا والد داره، نمیتونه سازنده های جفتشون رو به ارث ببره.
  2. مقدار دهی اولیه به اعضای کلاس
    [cpp]
    class SomeClass {
    int value = 5;
    };
    [/cpp]