Skip to content
Snippets Groups Projects
Commit 5e484516 authored by Jasper Clemens Gräflich's avatar Jasper Clemens Gräflich
Browse files

Add captions and abbreviations to 1.1.1

parent dd58444a
No related branches found
No related tags found
No related merge requests found
Pipeline #86548 passed
......@@ -7,7 +7,7 @@
In most programming languages, one can freely create and delete resources. For example, in C the programmer allocates memory on the heap with \lstinline{malloc} and frees the memory when they don’t need the memory anymore using \lstinline{free}.
\begin{lstlisting}[language=C]
\begin{lstlisting}[language=C, caption={Memory management in C}]
// Allocate space for an `int`.
int *ptr = (int*) malloc(sizeof(int));
......@@ -19,7 +19,7 @@ In most programming languages, one can freely create and delete resources. For e
Even in languages without manual memory management, the programmer still must manage other resources. For example, to work with a file in Python one could write:
\begin{lstlisting}[language=Python]
\begin{lstlisting}[language=Python, caption={Manual resource management in Python}]
# Open the file and store the file handle in a variable.
file = open("path/to/some.file", "r")
......@@ -31,11 +31,11 @@ file.close()
\paragraph{Resource Handling Strategies}
This manual resource management comes with some difficulties. The programmer has to watch out to always free the resources after using them, because otherwise the program could leak memory or unneccessarily inhibit other processes from accessing the resources. On the other hand, one may also not free the resources too early, which would lead to a use after free, and also not free resources multiple times. This can be very tricky in complex programs where resources are shared between threads or over API boundaries.
This manual resource management comes with some difficulties. The programmer has to watch out to always free the resources after using them, because otherwise the program could leak memory or unneccessarily inhibit other processes from accessing the resources. On the other hand, one may also not free the resources too early, which would lead to a use after free, and also not free resources multiple times. This can be very tricky in complex programs where resources are shared between threads or over \acs{API} boundaries.
That is why several programming languages have ways to make handling resources easier. Python has context managers that close resources automatically.
\begin{lstlisting}[language=Python]
\begin{lstlisting}[language=Python, caption={Context managers in Python}]
with open("path/to/some.file", "r") as file:
#...
......@@ -46,7 +46,7 @@ This code is equivalent to the previous one, but even better: It also closes the
Other languages have different strategies. Go supports the \lstinline{defer} statement which takes an operation that is not to be run immediately but at the end of the scope.
\begin{lstlisting}[language=Go]
\begin{lstlisting}[language=Go, caption={The \lstinline{defer} statement in Go}]
{ // Block starts here.
file, err := os.Open("path/to/some.file")
defer file.Close()
......@@ -59,11 +59,11 @@ Other languages have different strategies. Go supports the \lstinline{defer} sta
These prevent double frees and use after free errors, but they can still be forgotten. A programmer who wants to use a resource must be aware that it has to be cleaned up
in the end and changes in one line of the code have to be mirrored in the other. It is not as bad as in manual resource management because the programmer has to change only one additional line and that line is usually close.
\paragraph{RAII and Drop Responsibilities}
\paragraph{\acs{RAII} and Drop Responsibilities}
A third variant is \emph{Resource Acquisition is Initialization (RAII)} or \emph{Scope-Bound Resource Management} used by C++ and Rust. This ensures that the destructor of an object is run when it goes out of scope, which will clean up automatically. An example is the \lstinline{std::unique_ptr} in C++. The pointer \emph{owns} the memory it points to, meaning when it is created, it automatically allocates memory on the heap and when it goes out of scope, it frees the memory.
A third variant is \acfi{RAII}, also called \acfi{SBRM}, used by C++ and Rust. This ensures that the destructor of an object is run when it goes out of scope, which will clean up automatically. An example is the \lstinline{std::unique_ptr} in C++. The pointer \emph{owns} the memory it points to, meaning when it is created, it automatically allocates memory on the heap and when it goes out of scope, it frees the memory.
\begin{lstlisting}[language=C++]
\begin{lstlisting}[language=C++, caption={\ac{RAII} in C++}]
{ // Block starts here.
std::unique_ptr<int> ptr = std::make_unique<int>(42);
......@@ -72,9 +72,9 @@ A third variant is \emph{Resource Acquisition is Initialization (RAII)} or \emph
} // Block ends here; run the destructor and free the memory
\end{lstlisting}
RAII ensures that resources are always freed when they are not live (can’t be accessed) anymore. The programmer can’t forget to free the resources nor cause use after free or double free. While in C++ only objects conform to RAII, in Rust every value is owned by a variable. For example, the Rust analog to an owning pointer is \lstinline{Box}.
\ac{RAII} ensures that resources are always freed when they are not live (can’t be accessed) anymore. The programmer can’t forget to free the resources nor cause use after free or double free. While in C++ only objects conform to \ac{RAII}, in Rust every value is owned by a variable. For example, the Rust analog to an owning pointer is \lstinline{Box}.
\begin{lstlisting}[language=Rust]
\begin{lstlisting}[language=Rust,caption={Heap allocation in Rust}]
{ // Block starts here.
let ptr = Box::new(42)
......@@ -88,9 +88,9 @@ associated resources are freed. It is said that a variable has a \emph{drop resp
\paragraph{Move Semantics}
RAII comes with a few disadvantages, though. Since a value is dropped when its owner goes out of scope, ther must always be exactly one owner for every value. This means that the compiler will transfer ownership sometimes, like in the following example.
\ac{RAII} comes with a few disadvantages, though. Since a value is dropped when its owner goes out of scope, ther must always be exactly one owner for every value. This means that the compiler will transfer ownership sometimes, like in the following example.
\begin{lstlisting}[language=Rust]
\begin{lstlisting}[language=Rust,caption={Ownership transfer}]
fn print_value(ptr: Box<i32>) {
println!("{}", *ptr);
}
......@@ -116,7 +116,7 @@ Because we supplied \lstinline{ptr} as an argument to \lstinline{print_value}, i
We can still make it work by \emph{cloning} \lstinline{ptr} and supply the clone as an argument. \lstinline{ptr.clone()} creates a new \lstinline{Box}, allocates new memory, and initializes it with the same value as \lstinline{ptr}’s:
\begin{lstlisting}[language=Rust]
\begin{lstlisting}[language=Rust, caption={Usage of \lstinline{Clone}}]
fn print_value(ptr: Box<i32>) {
println!("{}", *ptr);
}
......@@ -137,7 +137,7 @@ Now everything works but keep in mind that the clone is completely independent f
We previously noted that ownership, and therefore move semantics, apply to every value in Rust. But if we change the code to use an \lstinline{i32} directly instead of putting it on the heap, we don’t need to clone anything:
\begin{lstlisting}[language=Rust]
\begin{lstlisting}[language=Rust, caption={Number types are \lstinline{Copy}}]
fn print_value(number: i32) {
println!("{}", number);
}
......@@ -153,7 +153,7 @@ fn main() {
This compiles and works. That is not because \lstinline{i32} breaks move semantics but because the type implements the \lstinline{Copy} trait. Normally, if a value is moved, the physical bits making up that value are moved to a new location, e. g. the new stack frame, and are not available at the previous position anymore. If a type implements \lstinline{Copy}, the bit pattern is instead copied over and retained. Because \lstinline{i32} doesn’t allocate any heap or handles any resources, such a copy is valid. A \lstinline{Box} is not \lstinline{Copy}, because then two owners for the same resource would exist which would violate drop responsibility. If we want to duplicate a \lstinline{Box}, we need to allocate new memory on the heap and initialize it properly, which is what \lstinline{clone} does.
\paragraph{Manually Drop} Sometimes we don’t want RAII to happen, we want to free resources ourselves. If that is the case, we can wrap a value in a \lstinline{ManuallyDrop} which tells the compiler to not drop it for us. More information can be found in the documentation for the type.\footnote{\url{https://doc.rust-lang.org/stable/std/mem/struct.ManuallyDrop.html}}
\paragraph{Manually Drop} Sometimes we don’t want \ac{RAII} to happen, we want to free resources ourselves. If that is the case, we can wrap a value in a \lstinline{ManuallyDrop} which tells the compiler to not drop it for us. More information can be found in the documentation for the type.\footnote{\url{https://doc.rust-lang.org/stable/std/mem/struct.ManuallyDrop.html}}
\subsection{Borrowing}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment