When constructing and deleting objects, shared_ptr works basically like unique_ptr. Constructing shared pointers works similarly as creating unique pointers (although there is a function make_shared that creates shared objects as a pendant to unique_ptr pointer's make_unique function).
The major difference from unique_ptr is that we can copy the shared_ptr instances because shared pointers maintain a so-called control block together with the object they manage. The control block contains a pointer to the payload object and a reference counter or use counter. If there are N number of shared_ptr instances pointing to the object, then the use counter also has the value N. Whenever a shared_ptr instance is destructed, then its destructor decrements this internal use counter. The last shared pointer to such an object will hit the condition that it decrements the use counter to 0 during its destruction. This is, then, the shared pointer instance, which calls the delete operator on the payload object! This way, we can't possibly suffer from memory leaks because the object's use count is automatically tracked.
To illustrate this a bit more, let's have a look at the following diagram:

In step 1, we have two shared_ptr instances managing an object of type Foo. The use counter is at value 2. Then, shared_ptr2 is destroyed, which decrements the use counter to 1. The Foo instance is not destroyed yet because there is still the other shared pointer. In step 3, the last shared pointer is destroyed too. This leads to the use counter being decremented to 0. Step 4 happens immediately after step 3. Both the control block and the instance of Foo are destroyed and their memory is released to the heap.
Equipped with shared_ptr and unique_ptr, we can automatically deal with most dynamically allocated objects without having to worry about memory leaks any longer. There is, however, one important caveat to consider--imagine we have two objects on the heap that contain shared pointers to each other, and some other shared pointer points to one of them from somewhere else. If that external shared pointer goes out of scope, then both objects still have the use counters with nonzero values because they reference each other. This leads to a memory leak. Shared pointers should not be used in this case because such cyclic reference chains prevent the use counter of such objects to ever reach 0.