Modern C++ or Rust - Basic borrowing system concept
Tags: cpp, rust
Published: 2023-07-03 16:28:12

Both C++ and Rust are fast, powerful programming languages. Both have pros and cons. This blog is my comparison and opinion of both programming languages by intermediate C, C++ and beginner Rust programmer.

> Note:
> I also code in TypeScript, JavaScript, Snail (Python) and couple other

## Opinion

In my opinion with Modern C++ you may not need Rust. Why?
Short answer:
C++ has concept known as 'smart pointers', with them, you can easily imitate Rust's borrowing system mainly with `unique_ptr`

## The long answer

It's not simple as `unique_ptr`, unique smart pointer has an issue and that is it can point to the same memory only once. That's why there is `shared_ptr` an another smart pointer that keeps track of how many of shared smart pointers are pointing to the same object in memory.

In rust
```rs
fn main() {
    let mut x = 4;
    let mut y = &mut x;
    let mut z = &mut x; // Cannot borrow more than once
}
```
is the same as
```cpp
#include <memory>

int main() {
    auto x = std::make_shared<int>(4);
    auto y = x;
    auto z = x;

    return 0;
}
```
In C++

However there is one issue. In rust, you can't borrow a variable as mutable more than one time. This is where C++ kind of wins, because you aren't limited to that restriction. However this gives you more boilerplate when getting the value out of the smart pointer.

Another example. What if we wanted to do something like
```rs
fn edit(val: &mut Vec<i32>) {
    val.push(7);
}

fn main() {
    let mut x = vec![4];
    // [4]
    edit(&mut x);
    // [4, 7]
}
```
Well, very simply and this time let's use unique smart pointer
```cpp
#include <vector>
#include <memory>

void edit(std::unique_ptr<std::vector<int>>& val) {
    val->push_back(7);
}

int main() {
    auto x = std::make_unique<std::vector<int>>();
    x->push_back(4);
    edit(x);
    return 0;
}
```

This is one of couple possible solutions, you don't even need smart pointer for this, just make stack allocated object of vector and pass it as reference.

Now let's say you want to move it and make the function own it. In C++ use `std::move` function, simple!

Rust
```rs
fn eat(mut val: Vec<i32>) {
    val.push(7);
}

fn main() {
    let mut x = vec![4];
    eat(x);
    println!("{:?}", x); // X inaccesible
}
```
C++
```cpp
#include <cstdio>
#include <vector>
#include <memory>

void eat(std::unique_ptr<std::vector<int>> val) {
    val->push_back(7);
}

int main() {
    auto x = std::make_unique<std::vector<int>>();
    x->push_back(4);
    eat(std::move(x));
    printf("%ld\n", x->size()); // x becomes nullptr
    return 0;
}
```

This is where magic of Rust compiler comes to play, It won't compile saying that the value `x` was moved. C++ compiler will compile this however the application will crash because `x` will be turned into `nullptr` yikes. You can check it either comparing it with `nullptr` or switching to `shared_ptr` and making `weak_ptr` and calling `expired` on the weak smart pointer. Like so
```cpp
    std::weak_ptr<std::vector<int>> hm = x;
    eat(std::move(x));
    printf("%d\n", hm.expired());
```
But you shouldn't move `shared_ptr` 🙂
Don't mimic Rust's borrowing system, you'll be regretting it.

And we're at the end. I know i left out so many features of Rust but all can be done in C++ as well.

I showed you some examples on how to make your C++ safe as Rust can but with more boilerplate and complex overhead. I hope you liked the blog post! Let me know by leaving a comment 💖 As a bonus, i'll write some C++ memory safety tips

### C++ memory safety tips
1. `new` should not be used and is dangerous, because on some platforms `new` returns zero or throws an exception and that will turn into pile of problems. To avoid that, include `new` header like this `#include <new>` and change all `new` calls into `new(std::nothrow) ...`. This way, if `new` fails, it will return `nullptr`.
2. Switching from pointers to smart pointers takes a LOT of time and debugging and everything, so you can simply secure your current `new` calls, follow tip number 1
3. When allocating array with `new`, to free every single value from the array, use `delete[]`, not `delete`. With only `delete` you'll free only the ***first*** element of the array.