Middle
Πώς λειτουργεί ο μετρητής αναφορών στο std::shared_ptr;
sobes.tech AI
Απάντηση από AI
Ο μετρητής αναφορών στο std::shared_ptr αποθηκεύεται σε ένα ξεχωριστό αντικείμενο: το μπλοκ ελέγχου (control block).
Το μπλοκ ελέγχου δημιουργείται:
- Κατά την πρώτη δημιουργία ενός
std::shared_ptrαπό έναν δείκτη. - Κατά τη δημιουργία ενός
std::shared_ptrμε προσαρμοσμένο διαγραφέα ή allocator. - Κατά τη χρήση του
std::make_sharedήstd::allocate_shared.
Αυτό το μπλοκ ελέγχου περιέχει τουλάχιστον δύο μετρητές:
- Μετρητής ισχυρών αναφορών (strong count): Αυξάνεται κατά τη δημιουργία ή αντιγραφή ενός
std::shared_ptr. Μειώνεται κατά την καταστροφή ενόςstd::shared_ptr. Όταν αυτός ο μετρητής φτάσει το μηδέν, το διαχειριζόμενο αντικείμενο απελευθερώνεται. - Μετρητής αδύναμων αναφορών (weak count): Αυξάνεται κατά τη δημιουργία ενός
std::weak_ptrαπό έναstd::shared_ptr. Μειώνεται κατά την καταστροφή ενόςstd::weak_ptr. Το μπλοκ ελέγχου απελευθερώνεται όταν και οι δύο μετρητές — ισχυρός και αδύναμος — φτάσουν το μηδέν.
Η χρήση του std::make_shared προτιμάται έναντι της άμεσης δημιουργίας με new, καθώς μπορεί να κατανεμηθεί ο αντικείμενο και το μπλοκ ελέγχου σε ένα μόνο μπλοκ μνήμης, βελτιώνοντας την απόδοση και μειώνοντας τον κατακερματισμό.
Οι μετρητές είναι ατομικοί, καθιστώντας το std::shared_ptr ασφαλές για χρήση σε περιβάλλοντα πολλαπλών νημάτων, αν και η πρόσβαση στο διαχειριζόμενο αντικείμενο δεν συγχρονίζεται από προεπιλογή.
Παράδειγμα:
#include <iostream>
#include <memory>
struct MyObject {
int data;
MyObject(int d) : data(d) {
std::cout << "MyObject(" << data << ") δημιουργήθηκε\n";
}
~MyObject() {
std::cout << "MyObject(" << data << ") καταστράφηκε\n";
}
};
int main() {
std::shared_ptr<MyObject> ptr1 = std::make_shared<MyObject>(10);
// ισχυρός μετρητής: 1, αδύναμος μετρητής: 0
{
std::shared_ptr<MyObject> ptr2 = ptr1;
// ισχυρός μετρητής: 2, αδύναμος μετρητής: 0
std::weak_ptr<MyObject> weak_ptr = ptr1;
// ισχυρός μετρητής: 2, αδύναμος μετρητής: 1
if (auto locked_ptr = weak_ptr.lock()) {
// ισχυρός μετρητής: 3, αδύναμος μετρητής: 1 (πρόσκαιρα μέσα σε lock)
std::cout << "Δεδομένα αντικειμένου: " << locked_ptr->data << std::endl;
}
// ισχυρός μετρητής: 2, αδύναμος μετρητής: 1
} // το ptr2 βγαίνει από το scope
// ισχυρός μετρητής: 1, αδύναμος μετρητής: 1
// Το αντικείμενο δεν έχει ακόμη καταστραφεί, καθώς ο ισχυρός μετρητής == 1
{
std::weak_ptr<MyObject> weak_ptr2 = ptr1;
// ισχυρός μετρητής: 1, αδύναμος μετρητής: 2
} // το weak_ptr2 βγαίνει από το scope
// ισχυρός μετρητής: 1, αδύναμος μετρητής: 1
} // το ptr1 βγαίνει από το scope
// ισχυρός μετρητής: 0, αδύναμος μετρητής: 1
// Το αντικείμενο καταστρέφεται, καθώς ο ισχυρός μετρητής έφτασε το 0
// Το μπλοκ ελέγχου παραμένει μέχρι ο αδύναμος μετρητής να φτάσει το 0