Wednesday, March 20, 2024

The goal of a software developer must be to move far above the language syntax - a study of Rust's Ownership Model vs C++ shared_ptr and unique_ptr


 

I always say to my student community that the primary goal of a software engineer must be to move above the language syntax and the nittie gritties of a software language. We must look at the code more from a designers' perspective and less as a programmers' perspective.

As I am trying to pick up Rust programming language to train my students, one thing I noticed and delved into was the ownership model of the Rust language and I could easily map it with the C++ shared_ptr and unique_ptr implementation.

My son Ridit and I conducted a study on the move copy of C++ shared_ptr long time back and then we wrote this blog post.



The move copy assignment operator is a member function of the std::shared_ptr class in C++. It is used to assign the ownership of a shared pointer to another shared pointer. The move copy assignment operator is more efficient than the copy assignment operator because it does not need to create a new copy of the underlying object.
The move copy assignment operator takes a single argument, which is a reference to a shared pointer. The argument must be an rvalue, which means that it cannot be a reference to a named variable. The move copy assignment operator then transfers the ownership of the underlying object from the argument to the shared pointer that it is called on.

The move copy assignment operator is typically used when the shared pointer that it is called on is about to be destroyed. This allows the ownership of the underlying object to be transferred to another shared pointer, which prevents the object from being deleted.

Here is an example of how to use the move copy assignment operator:

std::shared_ptr<int> ptr1 (new int(10));
std::shared_ptr<int> ptr2;

ptr2 = std::move(ptr1);

std::cout << *ptr2 << std::endl; // prints 10

In this example, the move copy assignment operator is used to transfer the ownership of the underlying object from ptr1 to ptr2. After the move copy assignment operator is called, ptr1 will no longer be a valid shared pointer.

Here's a comparison between Rust's ownership model and C++ shared_ptr /unique_ptr model.

Rust's ownership model

It is a core concept that governs memory management in the language. Unlike some languages that rely on garbage collection, Rust uses a system with strict rules enforced by the compiler at compile time. This ensures memory safety and prevents issues like memory leaks or dangling pointers.

Here's a breakdown of the key aspects of Rust's ownership model:

  • Ownership: Every value in Rust has an associated variable that acts as its owner. This variable is responsible for the value's lifetime in memory.
  • Moves: When you assign a value to another variable, ownership is transferred (moved). The original variable can no longer be used after the move. This prevents data corruption and ensures clarity about who "owns" the data.
  • Borrows: In some situations, you might need to use data without taking ownership. Rust allows borrowing, where a reference is created to access the data owned by another variable. The borrow checker, a part of the compiler, ensures borrows are valid and don't violate ownership rules.
  • Lifetimes: Lifetimes are annotations that specify the lifetime of references. They help the borrow checker guarantee that borrowed data is still valid when it's used.

By understanding these concepts, you can write memory-safe and efficient Rust programs. The ownership model might seem to be complex at first, but it becomes intuitive with practice and leads to robust and reliable software.

C++'s Smart Pointers (unique_ptr and shared_ptr):

  • Manual memory management with control: You have more control over ownership transfer and lifetime management.
  • Unique_ptr: Ensures single ownership and automatic deallocation when it goes out of scope. Similar to moving semantics in Rust, but managed at runtime.
  • Shared_ptr: Allows multiple owners to share a resource. Requires manual memory management and can lead to dangling pointers if not used carefully.
  • More complex and error-prone: Requires careful handling of ownership and potential for memory leaks or dangling pointers if not used correctly.

So the main point for the student community is to pick up one Object Oriented language very thoroughly and then you will find similarities in other languages - you will be able to map it with your existing knowledge base.

So... move way above the language syntax and get the big picture like an expert.

No comments: