Skip to content

Commit 1a60065

Browse files
committed
---
yaml --- r: 56458 b: refs/heads/auto c: 2c99e3d h: refs/heads/master v: v3
1 parent 05f1818 commit 1a60065

File tree

5 files changed

+113
-272
lines changed

5 files changed

+113
-272
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@ refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0
1414
refs/tags/release-0.3.1: 495bae036dfe5ec6ceafd3312b4dca48741e845b
1515
refs/tags/release-0.4: e828ea2080499553b97dfe33b3f4d472b4562ad7
1616
refs/tags/release-0.5: 7e3bcfbf21278251ee936ad53e92e9b719702d73
17-
refs/heads/auto: 195911fca412527472233aee163782c3bca11517
17+
refs/heads/auto: 2c99e3dc3effce7e33b817aeb3f300e4e1a1c382
1818
refs/heads/servo: af82457af293e2a842ba6b7759b70288da276167
1919
refs/tags/release-0.6: b4ebcfa1812664df5e142f0134a5faea3918544c

branches/auto/doc/tutorial-ffi.md

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -139,74 +139,6 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
139139
For reference, the examples used here are also available as an [library on
140140
GitHub](https://github.com/thestinger/rust-snappy).
141141

142-
# Destructors
143-
144-
Foreign libraries often hand off ownership of resources to the calling code,
145-
which should be wrapped in a destructor to provide safety and guarantee their
146-
release.
147-
148-
A type with the same functionality as owned boxes can be implemented by
149-
wrapping `malloc` and `free`:
150-
151-
~~~~
152-
use core::libc::{c_void, size_t, malloc, free};
153-
154-
#[abi = "rust-intrinsic"]
155-
extern "rust-intrinsic" mod rusti {
156-
fn init<T>() -> T;
157-
}
158-
159-
// a wrapper around the handle returned by the foreign code
160-
pub struct Unique<T> {
161-
priv ptr: *mut T
162-
}
163-
164-
pub impl<'self, T: Owned> Unique<T> {
165-
fn new(value: T) -> Unique<T> {
166-
unsafe {
167-
let ptr = malloc(core::sys::size_of::<T>() as size_t) as *mut T;
168-
assert!(!ptr::is_null(ptr));
169-
*ptr = value;
170-
Unique{ptr: ptr}
171-
}
172-
}
173-
174-
// the 'self lifetime results in the same semantics as `&*x` with ~T
175-
fn borrow(&self) -> &'self T {
176-
unsafe { cast::transmute(self.ptr) }
177-
}
178-
179-
// the 'self lifetime results in the same semantics as `&mut *x` with ~T
180-
fn borrow_mut(&mut self) -> &'self mut T {
181-
unsafe { cast::transmute(self.ptr) }
182-
}
183-
}
184-
185-
#[unsafe_destructor]
186-
impl<T: Owned> Drop for Unique<T> {
187-
fn finalize(&self) {
188-
unsafe {
189-
let mut x = rusti::init(); // dummy value to swap in
190-
x <-> *self.ptr; // moving the object out is needed to call the destructor
191-
free(self.ptr as *c_void)
192-
}
193-
}
194-
}
195-
196-
// A comparison between the built-in ~ and this reimplementation
197-
fn main() {
198-
{
199-
let mut x = ~5;
200-
*x = 10;
201-
} // `x` is freed here
202-
203-
{
204-
let mut y = Unique::new(5);
205-
*y.borrow_mut() = 10;
206-
} // `y` is freed here
207-
}
208-
~~~~
209-
210142
# Linking
211143

212144
In addition to the `#[link_args]` attribute for explicitly passing arguments to the linker, an

branches/auto/doc/tutorial.md

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -868,27 +868,108 @@ fn first((value, _): (int, float)) -> int { value }
868868

869869
# Destructors
870870

871-
A *destructor* is a function responsible for cleaning up the resources used by
872-
an object when it is no longer accessible. Destructors can be defined to handle
873-
the release of resources like files, sockets and heap memory.
871+
C-style resource management requires the programmer to match every allocation
872+
with a free, which means manually tracking the responsibility for cleaning up
873+
(the owner). Correctness is left to the programmer, and it's easy to get wrong.
874874

875-
Objects are never accessible after their destructor has been called, so there
876-
are no dynamic failures from accessing freed resources. When a task fails, the
877-
destructors of all objects in the task are called.
875+
The following code demonstrates manual memory management, in order to contrast
876+
it with Rust's resource management. Rust enforces safety, so the `unsafe`
877+
keyword is used to explicitly wrap the unsafe code. The keyword is a promise to
878+
the compiler that unsafety does not leak outside of the unsafe block, and is
879+
used to create safe concepts on top of low-level code.
878880

879-
The `~` sigil represents a unique handle for a memory allocation on the heap:
881+
~~~~
882+
use core::libc::{calloc, free, size_t};
883+
884+
fn main() {
885+
unsafe {
886+
let a = calloc(1, int::bytes as size_t);
887+
888+
let d;
880889
890+
{
891+
let b = calloc(1, int::bytes as size_t);
892+
893+
let c = calloc(1, int::bytes as size_t);
894+
d = c; // move ownership to d
895+
896+
free(b);
897+
}
898+
899+
free(d);
900+
free(a);
901+
}
902+
}
881903
~~~~
882-
{
883-
// an integer allocated on the heap
884-
let y = ~10;
904+
905+
Rust uses destructors to handle the release of resources like memory
906+
allocations, files and sockets. An object will only be destroyed when there is
907+
no longer any way to access it, which prevents dynamic failures from an attempt
908+
to use a freed resource. When a task fails, the stack unwinds and the
909+
destructors of all objects owned by that task are called.
910+
911+
The unsafe code from above can be contained behind a safe API that prevents
912+
memory leaks or use-after-free:
913+
914+
~~~~
915+
use core::libc::{calloc, free, c_void, size_t};
916+
917+
struct Blob { priv ptr: *c_void }
918+
919+
impl Blob {
920+
fn new() -> Blob {
921+
unsafe { Blob{ptr: calloc(1, int::bytes as size_t)} }
922+
}
923+
}
924+
925+
impl Drop for Blob {
926+
fn finalize(&self) {
927+
unsafe { free(self.ptr); }
928+
}
929+
}
930+
931+
fn main() {
932+
let a = Blob::new();
933+
934+
let d;
935+
936+
{
937+
let b = Blob::new();
938+
939+
let c = Blob::new();
940+
d = c; // move ownership to d
941+
942+
// b is destroyed here
943+
}
944+
945+
// d is destroyed here
946+
// a is destroyed here
885947
}
886-
// the destructor frees the heap memory as soon as `y` goes out of scope
887948
~~~~
888949

889-
Rust includes syntax for heap memory allocation in the language since it's
890-
commonly used, but the same semantics can be implemented by a type with a
891-
custom destructor.
950+
This pattern is common enough that Rust includes dynamically allocated memory
951+
as first-class types (`~` and `@`). Non-memory resources like files are cleaned
952+
up with custom destructors.
953+
954+
~~~~
955+
fn main() {
956+
let a = ~0;
957+
958+
let d;
959+
960+
{
961+
let b = ~0;
962+
963+
let c = ~0;
964+
d = c; // move ownership to d
965+
966+
// b is destroyed here
967+
}
968+
969+
// d is destroyed here
970+
// a is destroyed here
971+
}
972+
~~~~
892973

893974
# Ownership
894975

@@ -903,22 +984,6 @@ and destroy the contained object when they go out of scope. A box managed by
903984
the garbage collector starts a new ownership tree, and the destructor is called
904985
when it is collected.
905986

906-
~~~~
907-
// the struct owns the objects contained in the `x` and `y` fields
908-
struct Foo { x: int, y: ~int }
909-
910-
{
911-
// `a` is the owner of the struct, and thus the owner of the struct's fields
912-
let a = Foo { x: 5, y: ~10 };
913-
}
914-
// when `a` goes out of scope, the destructor for the `~int` in the struct's
915-
// field is called
916-
917-
// `b` is mutable, and the mutability is inherited by the objects it owns
918-
let mut b = Foo { x: 5, y: ~10 };
919-
b.x = 10;
920-
~~~~
921-
922987
If an object doesn't contain garbage-collected boxes, it consists of a single
923988
ownership tree and is given the `Owned` trait which allows it to be sent
924989
between tasks. Custom destructors can only be implemented directly on types
@@ -942,7 +1007,7 @@ refer to that through a pointer.
9421007
## Owned boxes
9431008

9441009
An owned box (`~`) is a uniquely owned allocation on the heap. It inherits the
945-
mutability and lifetime of the owner as it would if there was no box:
1010+
mutability and lifetime of the owner as it would if there was no box.
9461011

9471012
~~~~
9481013
let x = 5; // immutable
@@ -956,8 +1021,8 @@ let mut y = ~5; // mutable
9561021

9571022
The purpose of an owned box is to add a layer of indirection in order to create
9581023
recursive data structures or cheaply pass around an object larger than a
959-
pointer. Since an owned box has a unique owner, it can only be used to
960-
represent a tree data structure.
1024+
pointer. Since an owned box has a unique owner, it can be used to represent any
1025+
tree data structure.
9611026

9621027
The following struct won't compile, because the lack of indirection would mean
9631028
it has an infinite size:
@@ -1027,6 +1092,7 @@ d = b; // box type is the same, okay
10271092
c = b; // error
10281093
~~~~
10291094

1095+
10301096
# Move semantics
10311097

10321098
Rust uses a shallow copy for parameter passing, assignment and returning values

0 commit comments

Comments
 (0)