W jaki sposób prawidłowo uzyskać adres w pamięci operacyjnej, pod którym zapisany jest obiekt?
Ja właśnie robię próby z manipulacją na obiektach (klonowanie, pożyczanie, przenoszenie własności itp) i paru rzeczy nie rozumiem.
Znalazłem dwa sposoby uzyskania tego adresu: https://stackoverflow.com/questions/35882994/is-there-any-way-to-get-the-address-of-a-struct-in-rust
Adres to chciałbym wyświetlać jako numer, który jednoznacznie określa dany obiekt. Przede wszystkim chodzi o to, żeby między innymi wypisać każdy przypadek utworzenia i zniszczenia obiektu. Ten numer jednoznacznie powinien wskazać, jest jest to jeden i ten sam obiekt.
Ostatecznie mam taki program:
struct Book
{
title: String,
}
impl Book
{
pub fn set_title_borrow(&mut self, tit : &String)
{
self.title = tit.clone();
}
pub fn set_title_move(&mut self, tit : String)
{
self.title = tit;
}
pub fn addr1(&self) -> usize
{
return (self as * const _) as usize;
}
pub fn addr2(&self) -> usize
{
return std::ptr::addr_of!(self) as usize;
}
pub fn new(name: String) -> Self {
let book: Book = Book {title: name};
println!("* Tworzenie 1 {} {} {}", book.addr1(), book.addr2(), book.title);
book
}
pub fn printaddr(&self)
{
println!(" Adres {} {} {}", self.addr1(), self.addr2(), self.title);
}
}
impl Drop for Book {
fn drop(&mut self) {
println!("# Niszczenie {} {} {}", self.addr1(), self.addr2(), self.title);
}
}
impl Clone for Book {
fn clone(& self) -> Book {
println!("* Klonowanie z {} {} {}", self.addr1(), self.addr2(), self.title);
let mut t = self.title.clone();
t.push_str(" kopia");
let cl = Book {title: t};
println!(" do {} {} {}", cl.addr1(), cl.addr2(), cl.title);
cl
}
}
fn create_book_and_return_it_with_ownership() -> Book
{
let book: Book = Book {title: String::from("Nowy")};
println!("* create_book_and_ {} {} {}", book.addr1(), book.addr2(), book.title);
book
}
fn take_ownership(book: Book) -> Book
{
println!(" take_owner stary {} {} {}", book.addr1(), book.addr2(), book.title);
let x = book.clone();
println!(" take_owner nowy {} {} {}", x.addr1(), x.addr2(), x.title);
return x;
}
fn borrow_test(book: &Book)
{
println!(" borrow_test {} {} {}", book.addr1(), book.addr2(), book.title);
}
fn main()
{
let book3 = Book::new(String::from("Trzeci"));
book3.printaddr();
let mut book = create_book_and_return_it_with_ownership();
book.printaddr();
book.set_title_move(String::from("Czwarty"));
book.printaddr();
let tit = String::from("Piaty");
book.set_title_borrow(&tit);
book.printaddr();
book.title = String::from("Pierwszy");
book.printaddr();
book = take_ownership(book);
book.printaddr();
borrow_test(&book);
book.printaddr();
let mut book2 = book.clone();
book.printaddr();
book2.printaddr();
book2.title = String::from("Drugi");
book.printaddr();
book2.printaddr();
book.printaddr();
book2.printaddr();
}
Uzyskałem taki wynik, ponumerowałem linie dla czytelności:
1. * Tworzenie 1 140736324356480 140736324356432 Trzeci
2. Adres 140736324356816 140736324356496 Trzeci
3. * create_book_and_ 140736324356464 140736324356416 Nowy
4. Adres 140736324356864 140736324356496 Nowy
5. Adres 140736324356864 140736324356496 Czwarty
6. Adres 140736324356864 140736324356496 Piaty
7. Adres 140736324356864 140736324356496 Pierwszy
8. take_owner stary 140736324356992 140736324356144 Pierwszy
9. * Klonowanie z 140736324356992 140736324355408 Pierwszy
10. do 140736324355696 140736324355408 Pierwszy kopia
11. take_owner nowy 140736324356392 140736324356144 Pierwszy kopia
12. # Niszczenie 140736324356992 140736324355808 Pierwszy
13. Adres 140736324356864 140736324356496 Pierwszy kopia
14. borrow_test 140736324356864 140736324356496 Pierwszy kopia
15. Adres 140736324356864 140736324356496 Pierwszy kopia
16. * Klonowanie z 140736324356864 140736324356048 Pierwszy kopia
17. do 140736324356336 140736324356048 Pierwszy kopia kopia
18. Adres 140736324356864 140736324356496 Pierwszy kopia
19. Adres 140736324357024 140736324356496 Pierwszy kopia kopia
20. Adres 140736324356864 140736324356496 Pierwszy kopia
21. Adres 140736324357024 140736324356496 Drugi
22. Adres 140736324356864 140736324356496 Pierwszy kopia
23. Adres 140736324357024 140736324356496 Drugi
24. # Niszczenie 140736324357024 140736324356448 Drugi
25. # Niszczenie 140736324356864 140736324356448 Pierwszy kopia
26. # Niszczenie 140736324356816 140736324356448 Trzeci
Nie rozumiem następujących rzeczy:
- Dlaczego adres w liniach 1 i 2 się różni, mimo, że to jeden i ten sam obiekt? Tak samo linie 3 i 4.
- Dlaczego drugi adres w liniach 4, 5, 6 jest ten sam, mimo, że to są trzy różne obiekty?
- Dlaczego linie 7 i 8 mają różny adres, mimo, że to jeden i ten sam obiekt.
Wygląda na to, że adres uzyskany poleceniem (self as * const _)
zmienia się za każdym razem, gdy obiekt wchodzi lub wychodzi z funkcji (mimo, że faktycznie nie następuje kopiowanie obiektu), a adres uzyskany funkcją std::ptr::addr_of!(self)
może być taki sam dla kilku obiektów.
W jaki sposób prawidłowo uzyskać adres pamięci dla danego obiektu? Może pierwsza metoda źle podaje adres, bo zmienia się wtedy, kiedy faktycznie pozostaje bez zmian.