4-bo‘lim
Havolalar va const
Havola - obyektning ikkinchi nomi; nusxa qachon qimmat va const nima uchun deyarli hamma joyda kerak.
Ushbu bo‘lim mundarijasi
Havola (reference) - mavjud obyektning ikkinchi nomi.
Bu C da yo'q tushuncha va u C++ kodining ko'rinishini tubdan o'zgartiradi.
Havola nima #
#include <print>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
int son = 10;
int& havola = son; // havola - son ning ikkinchi nomi
std::println("son = {}, havola = {}", son, havola);
havola = 20; // havola orqali o'zgartiramiz
std::println("havola = 20 dan keyin: son = {}", son);
son = 30; // asl nom orqali
std::println("son = 30 dan keyin: havola = {}", havola);
// Ikkalasining manzili BIR XIL
std::println("manzillar teng: {}", &son == &havola);
return 0;
}
son = 10, havola = 10
havola = 20 dan keyin: son = 20
son = 30 dan keyin: havola = 30
manzillar teng: true
havola yangi xotira egallamaydi. U shunchaki son ning
boshqa nomi.
Havolaning uchta qat'iy qoidasi bor:
| Qoida | Ma'nosi |
|---|---|
| Initsializatsiya majburiy | int& h; - kompilyatsiya xatosi |
| Boshqa obyektga o'tkazib bo'lmaydi | Bir marta bog'lanadi va shunday qoladi |
nullptr bo'la olmaydi | Har doim mavjud obyektga ishora qiladi |
Uchinchi qoida muhim: havola olgan funksiya obyekt
mavjudligiga ishonch hosil qilishi mumkin.
Ko'rsatkichda esa har doim nullptr tekshiruvi kerak.
Nusxa qachon qimmat #
struct KattaObyekt
{
std::vector<int> malumot;
std::string nom;
// Nusxa olinganda xabar beradi
KattaObyekt(std::string n, std::size_t hajm)
: malumot(hajm, 1), nom(std::move(n)) {}
KattaObyekt(const KattaObyekt& boshqa)
: malumot(boshqa.malumot), nom(boshqa.nom)
{
std::println(" [nusxa olindi: {} element]", malumot.size());
}
};
// Qiymat bo'yicha - NUSXA olinadi
void qiymatBoyicha(KattaObyekt obyekt)
{
std::println(" qiymat bo'yicha: {}", obyekt.nom);
}
// Havola bo'yicha - nusxa YO'Q
void havolaBoyicha(const KattaObyekt& obyekt)
{
std::println(" havola bo'yicha: {}", obyekt.nom);
}
int main()
{
KattaObyekt katta{"hisobot", 100000};
std::println("1. qiymat bo'yicha chaqiruv:");
qiymatBoyicha(katta);
std::println("2. havola bo'yicha chaqiruv:");
havolaBoyicha(katta);
return 0;
}
1. qiymat bo'yicha chaqiruv:
[nusxa olindi: 100000 element]
qiymat bo'yicha: hisobot
2. havola bo'yicha chaqiruv:
havola bo'yicha: hisobot
Farq shunchaki tezlikda emas - xotirada ham. Qiymat bo'yicha uzatishda vaqtinchalik nusxa uchun yangi xotira ajratiladi.
Amaliy qoida:
| Parametr turi | Qanday uzatish |
|---|---|
int, double, char, ko'rsatkich | Qiymat bo'yicha |
std::string, std::vector, sinflar | const& |
| O'zgartirish kerak bo'lsa | & (havola) |
| Funksiya nusxani saqlab qolsa | Qiymat bo'yicha (12-bo'lim) |
Birinchi qator ham muhim: kichik turlar uchun const&
foydasiz va hatto sekinroq bo'lishi mumkin - chunki
havola ham manzil orqali ishlaydi.
Amaliy chegara: obyekt 16 baytdan katta bo'lsa
const& ishlating.
const havola vaqtinchalik qiymatni ham qabul qiladi #
void chop(const std::string& matn)
{
std::println(" chop: '{}'", matn);
}
std::string yasa()
{
return "funksiyadan qaytgan";
}
int main()
{
std::string oddiy{"oddiy o'zgaruvchi"};
chop(oddiy); // mavjud obyekt
chop("to'g'ridan-to'g'ri satr"); // vaqtinchalik std::string yasaladi
chop(yasa()); // funksiya natijasi
chop(std::string(5, 'x')); // vaqtinchalik obyekt
// const BO'LMAGAN havola vaqtinchalik qiymatni QABUL QILMAYDI
// void ozgartir(std::string& m);
// ozgartir("satr"); // KOMPILYATSIYA XATOSI
return 0;
}
chop: 'oddiy o'zgaruvchi'
chop: 'to'g'ridan-to'g'ri satr'
chop: 'funksiyadan qaytgan'
chop: 'xxxxx'
const& shunchalik keng ishlatiladiconst std::string& parametri hamma narsani qabul
qiladi:
| Argument | const& | & (const emas) |
|---|---|---|
| O'zgaruvchi | Ha | Ha |
| Konstanta | Ha | Yo'q |
| Vaqtinchalik obyekt | Ha | Yo'q |
| Funksiya natijasi | Ha | Yo'q |
Sabab mantiqiy: vaqtinchalik obyektni o'zgartirishning ma'nosi yo'q - u keyingi qatorda yo'q bo'ladi.
Shuning uchun kiritma parametrlar uchun const&
standart tanlov bo'ldi.
Havola va ko'rsatkich #
int main()
{
int a = 10;
int b = 20;
int& havola = a;
int* korsatkich = &a;
std::println("boshlang'ich: a={} b={}", a, b);
// Ko'rsatkichni boshqa obyektga o'tkazish mumkin
korsatkich = &b;
*korsatkich = 99;
std::println("korsatkich b ga: a={} b={}", a, b);
// Havolani o'tkazib BO'LMAYDI - bu a ga yozish demakdir
havola = b;
std::println("havola = b: a={} b={}", a, b);
// Ko'rsatkich nullptr bo'la oladi
int* bosh = nullptr;
std::println("bosh korsatkich: {}", bosh == nullptr);
return 0;
}
boshlang'ich: a=10 b=20
korsatkich b ga: a=10 b=99
havola = b: a=99 b=99
bosh korsatkich: true
havola = b; obyektni o'zgartirdi, havolani emasUchinchi natijaga qarang: a ning qiymati 99 bo'ldi.
havola = b yozuvi "havolani b ga bog'la" degani
emas. U "havola ko'rsatayotgan obyektga b ning
qiymatini yoz" degani.
Havola bir marta bog'lanadi va umrining oxirigacha o'sha obyektga ishora qiladi.
| Havola | Ko'rsatkich | |
|---|---|---|
| Initsializatsiya | Majburiy | Ixtiyoriy |
| Qayta bog'lash | Mumkin emas | Mumkin |
nullptr | Mumkin emas | Mumkin |
| Arifmetika | Yo'q | Bor (p + 1) |
| Sintaksis | h.metod() | p->metod() |
| Qachon ishlatiladi | Deyarli har doim | Ixtiyoriylik kerak bo'lsa |
Zamonaviy C++ da xom ko'rsatkichlar asosan ixtiyoriy
bo'lishi mumkin bo'lgan joylarda qoladi. Egalik uchun
esa unique_ptr ishlatiladi (10-bo'lim).
Osilgan havola #
// XATO: mahalliy o'zgaruvchiga havola qaytariladi
const std::string& xatoFunksiya()
{
std::string mahalliy{"men funksiya tugagach yo'q bo'laman"};
return mahalliy; // mahalliy shu yerda yo'q qilinadi
}
// TO'G'RI: qiymat bo'yicha qaytarish
std::string togriFunksiya()
{
std::string mahalliy{"men xavfsiz ko'chiriladi"};
return mahalliy; // ko'chiriladi, nusxa emas
}
int main()
{
std::println("to'g'ri: {}", togriFunksiya());
std::println("");
std::println("xatoFunksiya() ni chaqirish - aniqlanmagan xulq.");
std::println("Kompilyator ogohlantiradi, lekin taqiqlamaydi.");
std::println("Bunday kodni ASan bilan ishga tushiring (19-bo'lim).");
return 0;
}
to'g'ri: men xavfsiz ko'chiriladi
xatoFunksiya() ni chaqirish - aniqlanmagan xulq.
Kompilyator ogohlantiradi, lekin taqiqlamaydi.
Bunday kodni ASan bilan ishga tushiring (19-bo'lim).
xatoFunksiya ichidagi mahalliy funksiya tugashi bilan
yo'q qilinadi. Qaytgan havola esa endi mavjud
bo'lmagan xotiraga ishora qiladi.
Bu osilgan havola (dangling reference) va uni ishlatish aniqlanmagan xulq-atvor.
Kompilyator buni sezadi va ogohlantiradi:
warning: reference to local variable 'mahalliy' returned
Lekin u faqat oddiy holatlarni sezadi. Havola bir necha funksiya orqali o'tsa - hech kim ogohlantirmaydi.
Qachon havola qaytarish to'g'ri:
| Holat | Misol |
|---|---|
| Sinf a'zosiga havola | v[0], obj.nom() |
| Parametrga havola | max(a, b) - ikkalasi ham tashqaridan |
| Statik obyektga havola | Kamdan-kam |
| Mahalliy obyektga | Hech qachon |
Konteyner elementiga havola #
int main()
{
std::vector<int> sonlar{10, 20, 30};
int& birinchi = sonlar[0];
std::println("birinchi = {}", birinchi);
birinchi = 99;
std::println("o'zgartirgandan keyin: {}", sonlar);
// XAVF: vektor o'sganda xotira KO'CHIRILISHI mumkin
std::println("");
std::println("sig'im: {}", sonlar.capacity());
for (int i = 0; i < 10; ++i) {
sonlar.push_back(i);
}
std::println("qo'shgandan keyin sig'im: {}", sonlar.capacity());
std::println("birinchi havola endi ISHONCHSIZ");
std::println("(xotira boshqa joyga ko'chgan bo'lishi mumkin)");
return 0;
}
birinchi = 10
o'zgartirgandan keyin: [99, 20, 30]
sig'im: 3
qo'shgandan keyin sig'im: 24
birinchi havola endi ISHONCHSIZ
(xotira boshqa joyga ko'chgan bo'lishi mumkin)
push_back sig'imdan oshib ketsa, vector yangi
xotira ajratadi va hamma elementni ko'chiradi.
Shundan keyin eski elementlarga olingan barcha havolalar, ko'rsatkichlar va iteratorlar yaroqsiz bo'ladi.
| Amal | Nima yaroqsizlanadi |
|---|---|
push_back (sig'im yetsa) | Hech nima |
push_back (sig'im yetmasa) | Hammasi |
insert, erase | O'sha joydan keyingilari |
clear, resize | Hammasi (yoki qismi) |
reserve | Hammasi |
Amaliy qoida:
Konteynerni o'zgartirayotganda unga olingan havolalarni saqlamang.
Agar saqlash kerak bo'lsa - indeks saqlang. Indeks ko'chirishdan omon qoladi.
Bu xato ASan bilan darhol topiladi (19-bo'lim).
const ning joyi muhim #
int main()
{
int a = 1;
int b = 2;
// const ko'rsatkichning nimasi o'zgarmas?
const int* p1 = &a; // ko'rsatilgan QIYMAT o'zgarmas
int* const p2 = &a; // KO'RSATKICH o'zgarmas
const int* const p3 = &a; // ikkalasi ham
// *p1 = 10; // XATO - qiymatni o'zgartirib bo'lmaydi
p1 = &b; // lekin ko'rsatkichni o'zgartirish mumkin
*p2 = 10; // qiymatni o'zgartirish mumkin
// p2 = &b; // XATO - ko'rsatkichni o'zgartirib bo'lmaydi
std::println("a = {}", a);
std::println("p1 endi b ga ishora qiladi: {}", *p1);
std::println("p3 orqali: {}", *p3);
return 0;
}
a = 10
p1 endi b ga ishora qiladi: 2
p3 orqali: 10
const ni o'ngdan chapga o'qing| Yozuv | O'qilishi |
|---|---|
const int* p | p - o'zgarmas int ga ko'rsatkich |
int* const p | p - int ga o'zgarmas ko'rsatkich |
const int* const p | O'zgarmas int ga o'zgarmas ko'rsatkich |
Yodlash usuli: const o'zidan chapdagi narsani
o'zgarmas qiladi. Chapda hech narsa bo'lmasa - o'ngdagini.
Amalda birinchi shakl eng ko'p uchraydi:
const char*, const int* va h.k.
Havolalarda esa muammo yo'q - havola o'zi doim
"o'zgarmas bog'lanish", shuning uchun int& const degan
yozuv umuman mavjud emas.
const to'g'riligi #
struct Hisob
{
std::string egasi;
int balans;
// const metod - obyektni O'ZGARTIRMAYDI
int balansOl() const
{
return balans;
}
// const emas - o'zgartiradi
void toldir(int summa)
{
balans += summa;
}
};
void korsat(const Hisob& h)
{
// const obyektda faqat const metodlarni chaqirish mumkin
std::println(" {} - {} so'm", h.egasi, h.balansOl());
// h.toldir(100); // KOMPILYATSIYA XATOSI
}
int main()
{
Hisob hisob{"Husanboy", 500000};
korsat(hisob);
hisob.toldir(250000);
korsat(hisob);
const Hisob ozgarmas{"Malika", 1000000};
korsat(ozgarmas);
// ozgarmas.toldir(1); // KOMPILYATSIYA XATOSI
return 0;
}
Husanboy - 500000 so'm
Husanboy - 750000 so'm
Malika - 1000000 so'm
const metod nima va'da qiladiint balansOl() const yozuvidagi oxirgi const -
"bu metod obyektni o'zgartirmaydi" degan va'da.
Foydasi:
| Foyda | Izoh |
|---|---|
const obyektlarda chaqirish mumkin | Aks holda ishlatib bo'lmaydi |
const& parametrlarda ishlaydi | Eng keng tarqalgan holat |
| Niyat kodda ko'rinadi | O'qish oson |
| Kompilyator tekshiradi | Tasodifiy o'zgartirish rad etiladi |
Amaliy qoida: metod obyektni o'zgartirmasa - doim
const deb belgilang.
Buni keyinroq qo'shish qiyin: const metod faqat boshqa
const metodlarni chaqira oladi, shuning uchun bitta
yetishmayotgan const butun zanjirni buzadi.
Bu const to'g'riligi (const correctness) deb
ataladi va u boshidan qilinishi kerak.
- O'zgaruvchi va unga havola yarating, manzillarini solishtiring.
- Havola orqali qiymatni o'zgartiring va asl nom orqali tekshiring.
- Katta obyektni qiymat va havola bo'yicha uzatib, nusxa sonini sanang.
const¶metrga vaqtinchalik obyekt bering.- Const bo'lmagan havolaga vaqtinchalik obyekt berishga urinib ko'ring.
havola = b;nima qilishini natija bilan tushuntiring.- Mahalliy obyektga havola qaytaruvchi funksiya yozing - kompilyator nima dedi?
- Vektorga element qo'shib, sig'im o'zgarishini kuzating.
const int*,int* constvaconst int* constni sinab ko'ring.constmetodli sinf yozing vaconstobyektda chaqiring.
Xulosa #
- Havola - mavjud obyektning ikkinchi nomi, yangi xotira egallamaydi.
- U majburiy initsializatsiya qilinadi va qayta bog'lanmaydi.
- Havola
nullptrbo'la olmaydi - obyekt mavjudligi kafolatlangan. - Katta obyektni qiymat bo'yicha uzatish butun nusxani ko'chiradi.
- Kiritma parametrlar uchun standart tanlov -
const T&. const&vaqtinchalik obyektlarni ham qabul qiladi,&esa yo'q.havola = b;havolani emas, obyektni o'zgartiradi.- Mahalliy obyektga havola qaytarish - osilgan havola va aniqlanmagan xulq.
- Konteynerni o'zgartirish unga olingan havolalarni yaroqsiz qilishi mumkin.
- Obyektni o'zgartirmaydigan metodni
constdeb belgilang.
Keyingi bo'limda funksiyalar va lambdalar bilan tanishamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.