فصل ۶: محدوده و طول عمر متغیرها در C++
🎯 هدف یادگیری
در پایان این فصل شما میتوانید:
- تفاوت محدوده (Scope) و طول عمر (Lifetime) متغیرها را درک کنید.
- انواع محدوده (محلی، بلوکی، سراسری) را بشناسید.
- رفتار Shadowing (پوشاندن متغیر) را تشخیص دهید و از مشکلاتش جلوگیری کنید.
- تفاوت متغیرهای static، global و local را بفهمید.
- نحوه صحیح استفاده از متغیرها بر اساس محدوده و طول عمرشان را یاد بگیرید.
۱. مقدمه
هر متغیری که در C++ تعریف میکنیم یک دامنه معتبر (Scope) و یک مدت زمان زنده بودن (Lifetime) دارد.
- Scope = کجا قابل دسترسی است.
- Lifetime = کی ساخته میشود و کی از بین میرود.
بیتوجهی به این مفاهیم میتواند باعث ایجاد باگهای بسیار سخت شود.
۲. انواع محدوده متغیرها (Scope)
۲.۱ محدوده بلوکی (Block Scope)
- متغیری که داخل
{}
تعریف میشود فقط همانجا معتبر است. - بعد از خروج از بلاک، متغیر حذف میشود.
#include <iostream>
using namespace std;
int main() {
int x = 10;
{
int y = 5;
cout << "x = " << x << ", y = " << y << endl;
}
// cout << y; // ❌ خطا: y خارج از دسترس است.
}
۲.۲ محدوده تابعی (Local Scope)
- متغیر داخل یک تابع فقط همان تابع میتواند بخواند/تغییر دهد.
- با هر بار فراخوانی تابع، متغیر محلی دوباره ساخته و مقداردهی میشود.
void test() {
int a = 0;
a++;
cout << a << endl;
}
int main() {
test(); // خروجی: 1
test(); // خروجی: 1 (هر بار a از صفر شروع میکند)
}
۲.۳ محدوده سراسری (Global Scope)
- متغیر خارج از همه توابع تعریف شود و همه جای فایل قابل دسترسی باشد (بعد از محل تعریف).
- اگر در چند فایل استفاده شود باید
extern
استفاده شود.
#include <iostream>
using namespace std;
int counter = 0; // متغیر سراسری
void inc() {
counter++;
}
int main() {
inc();
inc();
cout << counter; // خروجی: 2
}
⚠ استفاده بیش از حد از متغیرهای global میتواند باعث وابستگی زیاد و سختی در عیبیابی شود.
۳. Shadowing (پوشاندن متغیر)
اگر یک متغیر محلی همنام متغیر سراسری یا متغیر بیرونی باشد، متغیر محلی متغیر بیرونی را مخفی میکند.
int x = 100; // global
int main() {
int x = 50; // local → global x پنهان شد
cout << x << endl; // 50
cout << ::x << endl; // دسترسی به global: 100
}
📌 عملگر ::
= Scope Resolution Operator کمک میکند به متغیر global دسترسی پیدا کنیم.
۴. طول عمر (Lifetime) متغیرها
۴.۱ Auto (پیشفرض)
- هر متغیر محلی بدون
static
→ با ورود به بلوک ساخته میشود، با خروج حذف میشود.
۴.2 Static Local
- موقع اولین اجرای تابع مقداردهی اولیه میشود و تا پایان اجرای برنامه در حافظه باقی میماند.
- مقدارش حفظ میشود.
void counterFunc() {
static int cnt = 0;
cnt++;
cout << cnt << endl;
}
int main() {
counterFunc(); // 1
counterFunc(); // 2
counterFunc(); // 3
}
۴.۳ Global / Static Global
- متغیر global: در کل برنامه زنده است.
- متغیر static global: فقط در همان فایل دیده میشود، ولی تمام برنامه زنده میماند.
۵. مثال عملی ترکیب Scope و Lifetime
#include <iostream>
using namespace std;
int g = 0; // global
void test() {
int localVar = 0; // auto local
static int staticVar = 0; // static local
g++;
localVar++;
staticVar++;
cout << "g=" << g << ", localVar=" << localVar
<< ", staticVar=" << staticVar << endl;
}
int main() {
test();
test();
test();
}
خروجی:
g=1, localVar=1, staticVar=1
g=2, localVar=1, staticVar=2
g=3, localVar=1, staticVar=3
📌 دلیل:
g
→ global → مقدارش بین اجراها حفظ میشود.localVar
→ auto local → هر بار تازه ساخته میشود.staticVar
→ static local → فقط یک بار ساخته میشود و مقدارش حفظ میگردد.
۶. Scope Nesting (محدودههای تو در تو)
- محدودهها میتوانند داخل هم باشند.
- در محدوده داخلی، به متغیرهای محدوده خارجی (اگر همنام نباشند) دسترسی داریم.
int main() {
int a = 5;
{
int b = 10;
cout << a << ", " << b << endl; // a و b هر دو
}
// cout << b; // ❌ خطا
}
۷. نکات کلیدی
- متغیرهای محلی توصیه میشوند چون باعث کاهش اثرات جانبی میشوند.
- متغیرهای global فقط وقتی واقعاً لازم است استفاده شوند.
- از نامگذاری دقیق برای جلوگیری از Shadowing.
- از
static
برای حفظ وضعیت بین فراخوانیها بدون استفاده از global. - متغیرهای
const
با هر Scope رفتار خاص خود را دارند (برای مقدار ثابت).
۸. اشتباهات رایج
❌ استفاده بیش از حد از global → وابستگی زیاد، باگهای پنهان.
❌ تعریف دوباره متغیر با نام مشابه → Shadowing ناخواسته.
❌ فراموش کردن این که static متغیر را یک بار مقداردهی میکند.
❌ اشتباه گرفتن Scope با Lifetime.
۹. تمرینها
تمرین ۱
برنامهای بنویسید که متغیر global و یک متغیر local همنام داشته باشد و تفاوت دسترسی به آنها را نشان دهد.
تمرین ۲
یک تابع بنویسید که هر بار فراخوانی شد تعداد دفعات اجرا را با استفاده از static
ذخیره کند.
تمرین ۳
با استفاده از بلوکهای تو در تو بررسی کنید که کدام متغیرها در کجا قابل دسترسی هستند.
تمرین ۴ (چالش)
یک برنامه منوی ساده بسازید که از یک متغیر static
برای ذخیره تعداد دفعات انتخاب گزینه استفاده کند.
۱۰. جمعبندی این فصل
- Scope = بازه مکانی دسترسی متغیر.
- Lifetime = بازه زمانی وجود متغیر در حافظه.
- انواع Scope: local (بلوک/تابع)، global.
- انواع Lifetime: auto (پیشفرض)، static local، global/static global.
- استفاده صحیح از متغیرها بر اساس این مفاهیم به کاهش باگ و بهینهسازی کمک میکند.