Middle
Co wiesz o inteligentnych wskaźnikach w C++?
sobes.tech AI
Odpowiedź od AI
Inteligentne wskaźniki to opakowania RAII nad zwykłymi (surowymi) wskaźnikami w C++, zapewniające automatyczne zarządzanie czasem życia przydzielonej pamięci, zapobiegając wyciekom.
Główne typy inteligentnych wskaźników w bibliotece standardowej C++:
std::unique_ptrstd::shared_ptrstd::weak_ptr
std::unique_ptr
- Posiada zasób wyłącznie.
- Nie może być kopiowany, ale może być przenoszony.
- Używany do wyłącznego posiadania zasobu.
- Koszty dodatkowe są minimalne, równoważne z surowym wskaźnikiem.
// przykład unique_ptr
#include <memory>
#include <iostream>
int main() {
std::unique_ptr<int> ptr = std::make_unique<int>(10);
std::cout << *ptr << std::endl; // 10
// std::unique_ptr<int> ptr2 = ptr; // Błąd kompilacji: unique_ptr nie jest kopiowany
std::unique_ptr<int> ptr3 = std::move(ptr); // Przeniesienie własności
std::cout << *ptr3 << std::endl; // 10
// std::cout << *ptr << std::endl; // Nieokreślone zachowanie: ptr jest teraz pusty
return 0;
}
std::shared_ptr
- Pozwala wielu wskaźnikom współdzielić własność zasobu.
- Używa licznika odwołań. Pamięć jest zwalniana, gdy licznik osiąga zero.
- Może być kopiowany. Każda kopia zwiększa licznik odwołań.
- Ma wyższe koszty w porównaniu do
unique_ptrze względu na zarządzanie licznikiem.
// przykład shared_ptr
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> ptr1 = std::make_shared<int>(20);
std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 1)
std::shared_ptr<int> ptr2 = ptr1; // Kopiowanie, zwiększa use_count
std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 2)
std::shared_ptr<int> ptr3 = ptr1; // Kolejna kopia
std::cout << *ptr1 << " (use_count: " << ptr1.use_count() << ")" << std::endl; // 20 (use_count: 3)
return 0;
}
std::weak_ptr
- Nie posiada własności zasobu i nie zwiększa licznika odwołań.
- Używany do rozwiązania problemu cyklicznych odwołań między
shared_ptr. - Umożliwia dostęp do zasobu wskazywanego przez
shared_ptr, ale nie zapobiega jego usunięciu. - Aby uzyskać dostęp do zasobu, konieczne jest przekształcenie
weak_ptrwshared_ptrza pomocą metodylock().
// przykład weak_ptr
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<int> shared_ptr_int = std::make_shared<int>(30);
std::weak_ptr<int> weak_ptr_int = shared_ptr_int;
if (auto locked_ptr = weak_ptr_int.lock()) {
std::cout << *locked_ptr << std::endl; // 30
} else {
std::cout << "Zasób został zwolniony." << std::endl;
}
shared_ptr_int.reset(); // Zasób jest zwalniany
if (auto locked_ptr = weak_ptr_int.lock()) {
std::cout << *locked_ptr << std::endl;
} else {
std::cout << "Zasób został zwolniony." << std::endl; // Zasób został zwolniony.
}
return 0;
}
Używanie inteligentnych wskaźników jest dobrą praktyką we współczesnym C++, ponieważ znacznie zmniejsza prawdopodobieństwo błędów w zarządzaniu pamięcią.