"Rust의 uninitialized와 forget"의 두 판 사이의 차이

(새 문서: <source lang="rust"> enum Gender{ Male, Female } struct Person{ name:String, age:u32, gender:Gender } impl std::fmt::Debug for Person{ fn fmt(&self, w:&mut std...)
 
 
(같은 사용자의 중간 판 6개는 보이지 않습니다)
1번째 줄: 1번째 줄:
 +
[[분류:프로그래밍]]
 +
[[분류:Rust]]
 +
==uninitialized==
 +
러스트는 객체의 초기화, 혹은 객체를 참조하기 전에 객체를 생성하는 것을 강제한다. 그렇게 해야 초보자가 하기 쉬운 쓰레기값을 가진 객체를 사용하는 실수를 방지하기 위해서이다.
 +
 +
하지만 항상 그렇게 하는 것은 피곤할 수 있고, 초기화를 안해도 되는 객체 또한 있기 마련이다. 이를 위해서 Rust에서는 '''uninitialized'''함수를 제공한다.
 
<source lang="rust">
 
<source lang="rust">
enum Gender{
+
fn main() {
     Male,
+
     let num = unsafe{std::mem::uninitialized::<i32>()};
     Female
+
     println!("{}",num);
 
}
 
}
struct Person{
+
</source>
     name:String,
+
'''unitialized'''는 Rust 메모리 안전 관리 수칙에서 벗어나는 행위이기 때문에 '너 정말 이게 안전하지 않은 지 아니?라는 확인용인 '''unsafe'''구문 내에서만 사용할 수 있다. 이 코드를 실행하면 num의 값이 쓰레기 값인 걸 확인할 수 있다.
     age:u32,
+
 
     gender:Gender
+
<pre>
 +
    Finished dev [unoptimized + debuginfo] target(s) in 0.41s
 +
    Running `target\debug\tes.exe`
 +
0x00000086
 +
PS C:\Users\qwead\Documents\tes> cargo run
 +
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
 +
    Running `target\debug\tes.exe`
 +
0x00000098
 +
PS C:\Users\qwead\Documents\tes> cargo run
 +
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
 +
    Running `target\debug\tes.exe`
 +
0x000000f4
 +
PS C:\Users\qwead\Documents\tes> cargo run
 +
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
 +
    Running `target\debug\tes.exe`
 +
0x0000008b
 +
</pre>
 +
==forget==
 +
'''uninitialized'''가 객체를 생성할 때 Rust 메모리 관리 규칙을 벗어나는 방법을 제공한다면 '''forget'''은 객체를 삭제할 때 Rust 메모리 관리 규칙에서 벗어나는 방법을 제공한다.
 +
 
 +
Rust의 메모리 관리 규칙은 스코프가 끝날 때 그 스코프가 소유한 객체도 메모리를 해제한다. 이때 일반적인 객체가 아닌 파일IO관련 객체 혹은 동적메모리를 사용하는 객체의 경우 객체가 죽을 때 객체의 drop메소드가 호출되어 객체 자신이 정리할 시간을 제공한다.
 +
 
 +
하지만 '''forget'''은 drop메소드를 호출하지 않고 객체를 해제한다.
 +
<source lang="rust">
 +
fn main() {
 +
     {
 +
        let mut s = Vec::<u128>::new();
 +
        for _ in 0..std::u16::MAX as u32 * 16{
 +
            s.push(0u128);
 +
        }
 +
        let mut n = String::new();
 +
        println!("press any key");
 +
        std::io::stdin().read_line(&mut n);
 +
    }
 +
     let mut n = String::new();
 +
    println!("press any key");
 +
     std::io::stdin().read_line(&mut n);
 
}
 
}
impl std::fmt::Debug for Person{
+
</source>
     fn fmt(&self, w:&mut std::fmt::Formatter)->std::fmt::Result{
+
[[File:캡처223.PNG]]
          
+
 
         match self.gender{
+
[[File:캡처224.PNG]]
            Gender::Male=>write!(w, "He is "),
+
 
            Gender::Female=>write!(w, "She is ")
+
메모리를 정상적으로 확인하는 것을 볼 수 있다. 하지만 코드 중간에 forget함수를 삽입하여 drop메소드를 안 호출하고 객체를 제거하면
        }?;
+
<source lang="rust">
         return writeln!(w,"{} and {}-years-old", self.name, self.age);
+
fn main() {
 +
     {
 +
        let mut s = Vec::<u128>::new();
 +
        for _ in 0..std::u16::MAX as u32 * 16{
 +
            s.push(0u128);
 +
         }
 +
         let mut n = String::new();
 +
        println!("press any key");
 +
        std::io::stdin().read_line(&mut n);
 +
         std::mem::forget(s);
 
     }
 
     }
 +
    let mut n = String::new();
 +
    println!("press any key");
 +
    std::io::stdin().read_line(&mut n);
 
}
 
}
impl Drop for Person{
+
</source>
     fn drop(&mut self){
+
[[파일:캡처225.PNG]]
      //  std::mem::drop(self.name);
+
 
         println!("{:?} drop!",self);
+
[[파일:캡처226.PNG]]
 +
 
 +
보다시피 메모리가 줄어 들지 않는 것을 확인할 수 있다.
 +
 
 +
==이것들을 어떻게 사용할까?==
 +
여러군데 사용할 수 있는데 대표적으로는 합병정렬에서 사용할 수 있다.
 +
<source lang="rust">
 +
fn sub_merge_sort<T>(source: *mut[T], memory:*mut[T])where T:PartialEq + PartialOrd{
 +
let s:&mut[T] = unsafe{ std::mem::transmute::<_, &mut[T]>(source) };
 +
     let m:&mut[T] = unsafe{ std::mem::transmute::<_, &mut[T]>(memory) };
 +
    if s.len() > 1{
 +
        let len = s.len();
 +
        let (s1,s2,m1,m2);
 +
        unsafe{
 +
            s1 = std::mem::transmute::<_, &mut[T]>(&mut s[0..len/2]);
 +
            s2 = std::mem::transmute::<_, &mut[T]>(&mut s[len/2..len]);
 +
            m1 = std::mem::transmute::<_, *mut[T]>(&m[0..len/2]);
 +
            m2 = std::mem::transmute::<_, *mut[T]>(&m[len/2..len]);
 +
        }
 +
        sub_merge_sort(s1, m1);
 +
        sub_merge_sort(s2, m2);
 +
        let mem:&mut[T] = unsafe{ std::mem::transmute::<_, &mut[T]>(memory) };
 +
        let mut s1_it = s1.iter_mut();
 +
        let mut s2_it = s2.iter_mut();
 +
        let mut mem_it = mem.iter_mut();
 +
        let mut sv1= s1_it.next();
 +
         let mut sv2= s2_it.next();
 +
        loop{
 +
            let m = match mem_it.next(){
 +
                Some(v)=>v,
 +
                None=>break
 +
            };
 +
 +
            let switch =
 +
match (&sv1,&sv2){
 +
                (&None,& Some(_))=>2,
 +
                (&Some(_),& None)=>1,
 +
                (&Some(ref v1),&Some(ref v2))if v1 > v2=>2,
 +
(&Some(ref v1),&Some(ref v2))if v1 <= v2=>1,
 +
                _=>{break;}
 +
            };
 +
 +
match switch{
 +
2=>{
 +
//let sv = &mut sv2;
 +
let v = sv2.unwrap();
 +
std::mem::swap(m,v);
 +
sv2 = s2_it.next()
 +
},
 +
1=>{
 +
let v = sv1.unwrap();
 +
std::mem::swap(m,v);
 +
sv1 = s1_it.next()
 +
}
 +
_=>{}
 +
}
 +
        }
 +
 
 +
        let mut mi = m.iter_mut();
 +
        let mut si = s.iter_mut();
 +
        while let Some(sv) = si.next(){
 +
            let mv = mi.next().unwrap();
 +
std::mem::swap(sv,mv);
 +
        }
 
     }
 
     }
 
}
 
}
fn main() {
+
fn merge_sort<T>(source:&mut[T])where T:PartialEq + PartialOrd{
    let a =Person{name:String::from("Hong gildong"), age:33, gender:Gender::Male};
+
let mut tempMemory:Vec<T> = Vec::with_capacity(source.len());
 
+
for _ in 0..source.len(){
    let b:Person =unsafe{std::mem::uninitialized()};
+
unsafe{tempMemory.push(std::mem::uninitialized());}
    println!("{:?}",a);
+
}
    println!("{:?}",b);
+
sub_merge_sort(source as *mut[T], tempMemory.as_mut_slice() as *mut[T]);
   
+
for it in tempMemory{
    std::mem::forget(b);
+
std::mem::forget(it);
 +
}
 
}
 
}
 
 
</source>
 
</source>

2018년 11월 14일 (수) 13:14 기준 최신판

uninitialized

러스트는 객체의 초기화, 혹은 객체를 참조하기 전에 객체를 생성하는 것을 강제한다. 그렇게 해야 초보자가 하기 쉬운 쓰레기값을 가진 객체를 사용하는 실수를 방지하기 위해서이다.

하지만 항상 그렇게 하는 것은 피곤할 수 있고, 초기화를 안해도 되는 객체 또한 있기 마련이다. 이를 위해서 Rust에서는 uninitialized함수를 제공한다.

fn main() {
    let num = unsafe{std::mem::uninitialized::<i32>()};
    println!("{}",num);
}

unitialized는 Rust 메모리 안전 관리 수칙에서 벗어나는 행위이기 때문에 '너 정말 이게 안전하지 않은 지 아니?라는 확인용인 unsafe구문 내에서만 사용할 수 있다. 이 코드를 실행하면 num의 값이 쓰레기 값인 걸 확인할 수 있다.

    Finished dev [unoptimized + debuginfo] target(s) in 0.41s
     Running `target\debug\tes.exe`
0x00000086
PS C:\Users\qwead\Documents\tes> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target\debug\tes.exe`
0x00000098
PS C:\Users\qwead\Documents\tes> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target\debug\tes.exe`
0x000000f4
PS C:\Users\qwead\Documents\tes> cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target\debug\tes.exe`
0x0000008b

forget

uninitialized가 객체를 생성할 때 Rust 메모리 관리 규칙을 벗어나는 방법을 제공한다면 forget은 객체를 삭제할 때 Rust 메모리 관리 규칙에서 벗어나는 방법을 제공한다.

Rust의 메모리 관리 규칙은 스코프가 끝날 때 그 스코프가 소유한 객체도 메모리를 해제한다. 이때 일반적인 객체가 아닌 파일IO관련 객체 혹은 동적메모리를 사용하는 객체의 경우 객체가 죽을 때 객체의 drop메소드가 호출되어 객체 자신이 정리할 시간을 제공한다.

하지만 forget은 drop메소드를 호출하지 않고 객체를 해제한다.

fn main() {
    {
        let mut s = Vec::<u128>::new();
        for _ in 0..std::u16::MAX as u32 * 16{
            s.push(0u128);
        }
        let mut n = String::new();
        println!("press any key");
        std::io::stdin().read_line(&mut n);
    }
    let mut n = String::new();
    println!("press any key");
    std::io::stdin().read_line(&mut n);
}

캡처223.PNG

캡처224.PNG

메모리를 정상적으로 확인하는 것을 볼 수 있다. 하지만 코드 중간에 forget함수를 삽입하여 drop메소드를 안 호출하고 객체를 제거하면

fn main() {
    {
        let mut s = Vec::<u128>::new();
        for _ in 0..std::u16::MAX as u32 * 16{
            s.push(0u128);
        }
        let mut n = String::new();
        println!("press any key");
        std::io::stdin().read_line(&mut n);
        std::mem::forget(s);
    }
    let mut n = String::new();
    println!("press any key");
    std::io::stdin().read_line(&mut n);
}

캡처225.PNG

캡처226.PNG

보다시피 메모리가 줄어 들지 않는 것을 확인할 수 있다.

이것들을 어떻게 사용할까?

여러군데 사용할 수 있는데 대표적으로는 합병정렬에서 사용할 수 있다.

fn sub_merge_sort<T>(source: *mut[T], memory:*mut[T])where T:PartialEq + PartialOrd{
	let s:&mut[T] = unsafe{ std::mem::transmute::<_, &mut[T]>(source) };
    let m:&mut[T] = unsafe{ std::mem::transmute::<_, &mut[T]>(memory) };
    if s.len() > 1{
        let len = s.len();
        let (s1,s2,m1,m2);
        unsafe{ 
            s1 = std::mem::transmute::<_, &mut[T]>(&mut s[0..len/2]);
            s2 = std::mem::transmute::<_, &mut[T]>(&mut s[len/2..len]);
            m1 = std::mem::transmute::<_, *mut[T]>(&m[0..len/2]);
            m2 = std::mem::transmute::<_, *mut[T]>(&m[len/2..len]);
        }
        sub_merge_sort(s1, m1);
        sub_merge_sort(s2, m2);
        let mem:&mut[T] =  unsafe{ std::mem::transmute::<_, &mut[T]>(memory) };
        let mut s1_it = s1.iter_mut();
        let mut s2_it = s2.iter_mut();
        let mut mem_it = mem.iter_mut();
        let mut sv1= s1_it.next();
        let mut sv2= s2_it.next();
        loop{
            let m = match mem_it.next(){
                Some(v)=>v,
                None=>break
            };
			
            let switch =
			match (&sv1,&sv2){
                (&None,& Some(_))=>2,
                (&Some(_),& None)=>1,
                (&Some(ref v1),&Some(ref v2))if v1 > v2=>2,
				(&Some(ref v1),&Some(ref v2))if v1 <= v2=>1,
                _=>{break;}
            };
			
			match switch{
				2=>{
					//let sv = &mut sv2;
					let v = sv2.unwrap();
					std::mem::swap(m,v);
					sv2 = s2_it.next()
				},
				1=>{
					let v = sv1.unwrap();
					std::mem::swap(m,v);
					sv1 = s1_it.next()
				}
				_=>{}
			}
        }

        let mut mi = m.iter_mut();
        let mut si = s.iter_mut();
        while let Some(sv) = si.next(){
            let mv = mi.next().unwrap();
			std::mem::swap(sv,mv);
        }
    }
}
fn merge_sort<T>(source:&mut[T])where T:PartialEq + PartialOrd{
	let mut tempMemory:Vec<T> = Vec::with_capacity(source.len());
	for _ in 0..source.len(){
		unsafe{tempMemory.push(std::mem::uninitialized());}
	}
	sub_merge_sort(source as *mut[T], tempMemory.as_mut_slice() as *mut[T]);
	for it in tempMemory{
		std::mem::forget(it);
	}
}