I thought I'd point out something about the concept of shared ownership, which is sometimes referred to as shared containment.
The slightly oversimplified way of putting this is ownership is determined by what deletes the object.
When something is allocated on the stack, as the case with local variables to a function, one might say the function owns the storage, and that certainly isn't shared. If you passed a pointer to such a variable to a function, the ownership is still not shared, because only one thing will ever delete the object (the end of the function, when the stack is cleaned up).
Similarly, with unique_ptr, the only thing that will ever delete the object will be the unique_ptr when it is destroyed.
It is with shared_ptr that we come to the concept of shared containment. Many shared_ptr instances may "hold" onto one underlying object, each with the responsibility to delete the object under one and only one circumstance: when that shared_ptr is recognized to be the last one holding the object. It does that through reference counting.
In this paradigm, any of the multiple shared_ptr instances may delete the object, but only under that circumstance when the shared_ptr itself is being destroyed and at the moment it "recognizes" there are no other shared_ptrs holding on to that object at that time. This "moment of destruction" is the act of containment when that containment reaches its conclusion, and defines the fundamental meaning of ownership, shared or not. It is shared when any of the holding objects (shared_ptr in this case) can be the destroyer of the underlying object, but it is not shared when only one object can ever be the destroyer of the underlying object.
Since unique_ptr allows for moving ownership, I should point out that even though an object may be moved from one unique_ptr to another, this isn't "shared" - it is transferred. The receiving unique_ptr accepts ownership while it is surrendered by the provider.
Raw pointers which receive the result of an allocation (be it new, malloc or something related) have no "automatic" containment strategy, since the raw pointer itself has no destructor that can be called. The programmer must "manually" perform deletion, and it is a known source of bugs. It was (and still is) the way C must work, but in C++ is it something to avoid. The same applies to closing files that are opened, or releasing device contexts when they're no longer needed.
It is the destructor function which is key to making classes that act as containers, be they smart pointers or more complex containers like lists, maps or vectors. The cycle by which creation and destruction "owns" an object is known as "RAII", a name Stroustrup slightly regrets as non-descriptive because it means "Resource acquisition is initialization". Not a clear phrase. What it is supposed to mean is that when a resource is created (through new, malloc, open..., create....), then if that creation initializes an "owner", then the release of that resource can be automatic at the owning class' destruction. It applies to the opening and closing of files with the file stream classes, with memory where containers and smart pointers are concerned, and with device contexts in GUI code.
The idea is that you should not leave the "closing" of a resource to a separate step that you might forget. It should be "automatic" as the result of a class which controls the open and close cycle through it's constructor and destructor functions. This is the essence of ownership.
In C++ it takes a secondary role, where resources acquired this way are released appropriately when an exception fires. Without using a class (on the stack) that "owns" a resource (memory, file, whatever), then an exception would have to be written to explicitly (and manually) figure out what must be closed, or freed, or whatever. By using classes for RAII, the destructors are automatically called to release resources when an exception is thrown.
This is a benefit to smart pointers not often discussed until later in the study.