C++11 yangiliklari va imkoniyatlari
Rasmiy ravishda ISO/IEC 14882:2011 nomi bilan tanilgan C++ 11 2011 yilda chiqarilgan va C++ dasturlash tili evolyutsiyasida muhim bosqich boʻlgan.
U C++ ni yanada kuchliroq qiladigan ko'plab yangi xususiyatlar va yaxshilanishlarni taqdim etdi.
Mana C++ 11 da kiritilgan eng muhim xususiyatlar:
auto kalit so'zifor sikliconstexpr kalit so'zinullptr kalit so'ziauto kalit so'zini o'rganishdan boshlaylik.
auto kalit so'zi C++ 11 ga o'zgaruvchining turini o'z initsializatoridan avtomatik ravishda chiqarish imkonini beradi.
#include <iostream>
using namespace std;
int main() {
// x int sifatida chiqariladi
auto x = 42;
// pi ikki barobar qilib chiqariladi
auto pi = 3.1415926535;
cout << "x: " << x << endl;
cout << "pi: " << pi << endl;
return 0;
}
Chiqish
x: 42
pi: 3.14159
Bu erda kompilyator x va pi o'zgaruvchilarining turini ularning initsializatoridan chiqarib tashlashga qodir, shuning uchun ularning turini aniq aytib o'tishimiz shart emas. Biroq, auto dan foydalanilganda, o'zgaruvchi har doim ishga tushirilishi kerak.
auto x; // xato: har doim ishga tushirilishi kerak
[!NOTE]
auto- bu C++ tilidagi turning o'zi emas, balki turni to'ldiruvchisidir. Shunday qilib, unisizeofyokitypeidkabi translatsiyalarda yoki operatorlarda ishlatib bo'lmaydi.
Range based for loops in C++ executes a loop for a range.
Sintaksis
for (range_initialization : range_container) {
// sikl operatorlari
}
Bu yerga,
Masalan,
vector<int> numbers = {1, 2, 3};
// raqamlar vektori bo'ylab aylanish
for (int num : numbers) {
// vektor elementini chop etish
cout << num << endl;
}
[!NOTE] range-based-loops should be preferred over normal for loops whenever possible to avoid out of bound errors.
#include <iostream>
#include <vector>
using namespace std;
int main() {
// butun sonlar vektorini yarating
vector<int> numbers = {1, 2, 3, 4, 5};
// diapazonga vosita for loopdan foydalanish
// vektor orqali takrorlash
for (const auto& num : numbers) {
cout << num << " ";
}
return 0;
}
Chiqish
1 2 3 4 5
Bu erda biz num takrorlanuvchi o'zgaruvchini e'lon qildik va range based for loop. yordamida konteyner raqamlarini takrorladik.
Lambda ifodalari qisqacha anonim funksiyalarni yaratishga imkon beradi. Ular, ayniqsa, kichik funksiyalarni boshqa funksiyalarga argument sifatida o'tkazish kerak bo'lganda foydalidir.
Sintaksis
[capture_clause] (parameter_list) -> return_type {
// lambda tanasi: bajariladigan kod
}
Bu yerga,
[!NOTE] Turlarni avtomatik chegirib tashlash uchun return_type ni o'tkazib yuborishimiz mumkin, agar har xil turdagi bir nechta mumkin bo'lgan qaytarish qiymatlari bo'lmasa.
Batafsil ma’lumot olish uchun C++ Lambda qo‘llanmamizga tashrif buyuring.
#include <iostream>
using namespace std;
int main() {
// "qo'shish" deb nomlangan lambda funksiyasini aniqlang
// bu ikkita butun sonni oladi va ularning yig'indisini qaytaradi
auto add = [] (int a, int b) {
return a + b;
};
// 3 va 4 argumentlar bilan lambdani chaqiring
int result = add(3, 4);
// natijani chop eting.
cout << "Result: " << result << endl;
return 0;
}
Chiqish
Result: 7
Bu yerda biz add() lambda funksiyasini yaratdik, u ikkita a va b argumentlarini oladi va ularning summasini qaytaradi.
C++ 11 xotirani avtomatik boshqaradigan va xotira oqishini oldini olishga yordam beruvchi aqlli ko‘rsatkichlarni taqdim etdi. Asosan, aqlli ko'rsatkich amaldan tashqariga chiqqanda o'zi boshqaradigan xotirani avtomatik ravishda chiqaradi.
Aqlli ko'rsatkichlar ikki xil:
Sintaksis
// noyob ko'rsatkich
std::unique_ptr<data_type> unique_pointer = std::make_unique<data_type>(args...);
// umumiy ko'rsatkich
std::shared_ptr<Type> shared_pointer = std::make_shared<data_type>(args...);
[!NOTE] Aqlli ko'rsatkichlardan foydalanish uchun
<memory>sarlavha faylini import qilishimiz kerak.
#include <iostream>
#include <memory>
using namespace std;
int main() {
// qiymati 42 bo'lgan butun songa umumiy ko'rsatkich yarating
shared_ptr<int> shared_pointer = make_shared<int>(42);
// qiymati 3.14 bo'lgan dublga noyob ko'rsatkich yarating
unique_ptr<double> unique_pointer = make_unique<double>(3.14);
// shared_ptr tomonidan ko'rsatilgan qiymatni chop eting
cout << "shared_pointer: " << *shared_pointer << endl;
// unique_ptr tomonidan ko'rsatilgan qiymatni chop eting
cout << "unique_pointer: " << *unique_pointer << endl;
return 0;
}
Chiqish
shared_pointer: 42
unique_pointer: 3.14
Ko'chirish semantikasi ob'ektga tegishli resurslarni nusxalash o'rniga boshqa ob'ektga ko'chirish imkonini beradi. Bu chuqur nusxalardan qochib ishlashni optimallashtiradi.
Biz harakat semantikasini amalga oshirish uchun move() funksiyasidan foydalanamiz. Masalan,
#include <iostream>
#include <vector>
using namespace std;
int main() {
// butun son vektorini yarating
vector<int> source = {1, 2, 3};
// manba tarkibini boshqa vektorga o'tkazing
vector<int> destination = move(source);
// maqsad vektorini chop eting
cout << "Destination Vector Contents: ";
for (const int num : destination) {
cout << num << " ";
}
// maqsad vektorining o'lchamini chop eting
cout << "\nDestination Vector Size: " << destination.size();
return 0;
}
Chiqish
Destination Vector Contents: 1 2 3
Destination Vector Size: 3
Bu erda biz move() funksiyasidan tarkibni manbadan manzilga ko'chirish uchun foydalandik.
vector<int> destination = move(source);
constexpr kalit so'zi o'zgaruvchi yoki funksiyani kompilyatsiya vaqtida baholash mumkinligini belgilash imkonini beradi. Masalan,
constexpr int square(int x) {
return x * x;
}
// kompilyatsiya vaqtida hisoblangan
int result = square(5);
Bu erda biz constexpr kalit so'zidan square() funksiyasi bilan foydalandik. Natijada, square(5) ishlash vaqtida emas, balki kompilyatsiya vaqtida baholanishi mumkin.
Bu kodning ishlashini oshirishi mumkin va ifodalar kompilyatsiya vaqtida ma'lum bo'lgan qiymat bilan ishga tushirilishini ta'minlaydi.
nullptr ning kiritilishi null ko'rsatkichlar uchun NULL dan foydalanishga xavfsizroq alternativani taqdim etadi.
int* ptr = nullptr;
[!NOTE]
nullptrNULLxavfsizligini ta'minlaganligi sababli har doimnullptrniNULLdan afzal ko'ring.
C++ tilida tip belgilari kompilyatsiya vaqtida turlar haqida ma’lumot to‘plash uchun ishlatiladigan shablonlar guruhi bo‘lib, shablonlarni metadasturlash uchun kuchli vosita hisoblanadi.
Bu shuni anglatadiki, dasturingiz ishga tushishidan oldin kompilyator siz foydalanayotgan turlar haqida, masalan, tur butun son bo'ladimi, uni nusxalash mumkinmi yoki u ma'lum funksiyaga ega sinfmi yoki yo'qligini tushunishi mumkin.
Ular standart andozalar kutubxonasining (STL) bir qismidir va <type_traits> sarlavha fayliga kiritilgan.
Tur belgilari class templates yoki function templates yordamida amalga oshiriladi. Mana, funksiya shablonining namuna kodi.
template <typename T>
void process(T value) {
if (std::is_pointer<T>::value) {
// ko'rsatkichlarni boshqarish
}
else if (std::is_integral<T>::value) {
// butun sonlarni boshqarish
}
}
C++ 11 mavzularni yaratish va boshqarish imkonini beruvchi standartlashtirilgan ish zarrachalari kutubxonasini qo'shdi.
#include <iostream>
#include <thread>
using namespace std;
void sayHello(){
cout << "Hello, from the spawned thread\n";
}
int main(){
// std::thread obyektini yarating
std::thread t(sayHello);
std::cout << "Hello, from the main thread\n";
// ip o'z ishini yakunlashini kuting
t.join();
}
Chiqish:
Hello, from the main thread
Hello, from the spawned thread
[!NOTE] Chiqish bajarilishga bog'liq, shuning uchun uni har safar ishga tushirganingizda bir xil natijaga erisha olmaysiz.
Har bir ipning boshlang'ich funksiyasi bo'lishi kerak, bu erda yangi ipning bajarilishi boshlanadi.
Shunday qilib, biz sayHello funksiyasini o'tkazish orqali std::thread t ob'ektini yaratdik, biz ip bajarilishini xohlaymiz.
Endi dasturda 2 ta ip mavjud - biri asosiy funksiyani bajaradi, ikkinchisi sayHello funksiyasini bajaradi.
C++ 11 da konstruktor xuddi shu sinfdagi boshqa konstruktorni chaqirishi mumkin. Masalan,
#include <iostream>
using namespace std;
class Complex {
int img;
int real;
public:
// №1 konstruktor (maqsadli konstruktor)
Complex(int i, int r) : img(i), real(r) {}
// №2 konstruktor (konstruktorni topshirish)
// maqsadli konstruktorga argument sifatida ikkita nolni o'tkazing
Complex() : Complex(0, 0) {
cout << "Delegating constructor" << endl;
cout << "img = " << img << endl;
cout << "real = " << real << endl;
}
};
int main() {
// Kompleks sinfining namunasini yarating
// vakolat beruvchi konstruktor yordamida
Complex obj;
return 0;
}
Chiqish
Delegating constructor
img = 0
real = 0
Bu erda vakolat beruvchi konstruktor maqsadli konstruktorni chaqiradi.
Ular ataylab o'chirilgan deb belgilangan a'zo funksiyalari. Bu shuni anglatadiki, funksiyalardan foydalanib bo'lmaydi va ularni chaqirishga har qanday urinish kompilyatsiya xatosiga olib keladi.
Funksiyalarni o'chirish sinfingizdagi muayyan operatsiyalarni oldini olishni istasangiz foydali bo'ladi.
class My_Class {
public:
// standart konstruktorni o'chirib tashlang
My_Class() = delete;
// a'zo funksiyasini o'chirish
void do_something() = delete;
};
Ular kompilyatordan ma'lum a'zo funksiyalari uchun standart ilovalarni yaratishni aniq so'rash uchun ishlatiladi.
Bu, ayniqsa, kompilyator tomonidan yaratilgan versiyalardan foydalanmoqchi bo'lganingizda foydali bo'ladi va shu bilan birga boshqa funksiyalar uchun shaxsiy xatti-harakatlarni ta'minlaydi.
class Another_Class {
public:
// kompilyator tomonidan yaratilgan standart konstruktordan foydalaning
Another_Class() = default;
// maxsus konstruktorni aniqlang
Another_Class(int x) : value(x) {}
private:
int value;
};
class Example {
public:
// sukut bo'yicha standart konstruktor
Example() = default;
// o'chirilgan nusxa konstruktori
Example(const Example&) = delete;
};
int main() {
// ruxsat berilgan: standart konstruktor ishlatiladi
Example obj1;
// xato: nusxa ko'chirish konstruktori o'chirildi
// Misol obj2 = obj1;
return 0;
}
Bu yerga,
Example sinfining ob'ektini yaratishimiz mumkin.Example ob'ektining nusxasini yarata olmaymiz, chunki nusxa ko'chirish konstruktori o'chirilgan.