banner
Matrix

Matrix

Abyss
email
github

Petty C++ Pointers

Smart Pointers#

Smart pointers in C++ are pointers used to manage dynamically allocated objects. They provide automatic memory management and help avoid memory leaks and dangling pointers. The C++ standard library provides two main smart pointers: std::unique_ptr and std::shared_ptr.

  1. std::unique_ptr:
    std::unique_ptr is a smart pointer that owns the sole ownership of the object. It ensures that only one pointer can access the given resource. When std::unique_ptr goes out of scope or is deleted, it automatically releases the managed object. It cannot be copied, but ownership can be transferred using move semantics. The std::make_unique function can be used to conveniently create std::unique_ptr objects.
{
  std::unique_ptr<int> ptr = std::make_unique<int>(42);
  std::cout << *ptr << std::endl;
}

// The object managed by ptr will be automatically released when ptr goes out of scope
  1. std::shared_ptr:
    std::shared_ptr is a smart pointer that allows multiple pointers to share ownership and keeps track of how many pointers reference the given resource. The managed object is only released when the last std::shared_ptr goes out of scope or is deleted. Ownership can be shared through copying or transferred using move semantics. The std::make_shared function can be used to conveniently create std::shared_ptr objects.

{
std::unique_ptr ptr1 = std::make_unique(42);
std::unique_ptr ptr2 = ptr1; // Shared ownership
}

// The objects managed by ptr1 and ptr2 will be automatically released when they go out of scope

The use of smart pointers can effectively manage dynamically allocated objects and avoid memory leaks and dangling pointers. However, it is important to note that smart pointers cannot solve all memory management issues, such as circular references that may prevent resources from being released. Therefore, when using smart pointers, careful design and management of object lifetimes are still necessary.

About shared pointers, using std::make_shared<Chunk>(position) as an example#

std::make_shared<Chunk>(position) is a syntax for creating a Chunk object using the std::make_shared function.

Specifically, this line of code uses angle brackets <Chunk> to specify the template argument, telling the std::make_shared function the type of object to create is Chunk. Then, the position inside the parentheses is the argument passed to the constructor of Chunk.

std::make_shared is a template function with the following definition:

template<typenameT, typename... Args>
shared_ptr<T> make_shared(Args&&... args);

It takes a variable number of arguments Args&&... args, which will be passed to the constructor of type T to create the object. In this example, T is Chunk type, and Args is the type of position.

The std::make_shared function returns a shared pointer of type shared_ptr<T>, which points to the T type object constructed with the passed arguments.

Therefore, the purpose of the code std::make_shared<Chunk>(position) is to create an object of type Chunk and manage its lifetime using a shared pointer. At the same time, position is passed as an argument to initialize the Chunk object during creation.

In practice, std::make_shared is primarily used for constructing new objects. It dynamically allocates memory on the heap and calls the object's constructor with the passed arguments.

If there is an existing instance and you want to wrap it in a shared pointer for management, you can use the constructor of std::shared_ptr or a variant of std::make_shared to achieve this.

The constructor of std::shared_ptr can wrap an existing pointer into a shared pointer.#

For example:

Chunk* existingChunk = new Chunk(position);
std::shared_ptr<Chunk> sharedChunk(existingChunk);

In this example, existingChunk is a pointer to an existing Chunk object, and by passing it to the constructor of std::shared_ptr, a shared pointer sharedChunk can be created to manage the lifetime of the object.

In this case, existingChunk should not be used further, as once sharedChunk is destroyed (or the last shared pointer owning it is destroyed), the memory it points to will be automatically released. Accessing existingChunk after that will result in undefined behavior, such as accessing released memory.

(Not recommended!)

Another approach is to use a variant of std::make_shared, namely std::allocate_shared:

Chunk* existingChunk = new Chunk(position);
std::shared_ptr<Chunk> sharedChunk = std::allocate_shared<Chunk>(std::allocator<Chunk>(), *existingChunk);

In this example, using std::allocate_shared<Chunk>(std::allocator<Chunk>(), *existingChunk) creates a new Chunk instance, and this new instance is initialized by copying the object pointed to by existingChunk. There is no conversion from a regular pointer existingChunk to a shared pointer, but rather a copy of the object occurs. std::allocate_shared uses the provided object (*existingChunk) as the argument for the copy constructor to create a new object, which is then managed by the returned shared pointer.

Creating a copy of an object and simultaneously keeping the original object pointed to by the original pointer using std::allocate_shared is generally not recommended. This approach can lead to several issues:

  1. Increased complexity in memory management: This method creates two independent object instances, one managed by the original pointer and the other managed by the shared pointer. This requires managing the lifetimes of these two objects separately, increasing the risk of memory leaks.

  2. Unclear design intent: The introduction of smart pointers (such as std::shared_ptr) is primarily to simplify memory management by automatically managing the lifetimes of objects and reducing the risks of memory leaks and dangling pointers. By copying the object instead of taking ownership of the original pointer, you are not effectively utilizing the main advantage of smart pointers.

  3. Performance overhead: Copying objects can involve significant performance overhead, especially when the objects are large or the copy operation is expensive. If there is no need to create a copy of the object, this overhead can be avoided.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.