Интеллектуальный указатель - это класс, который оборачивает «необработанный» (или «голый») указатель C ++ для управления временем жизни объекта, на который указывает указатель. Не существует единого типа интеллектуального указателя, но все они пытаются абстрагировать необработанный указатель практическим способом.
Умные указатели должны быть предпочтительнее сырых указателей. Если вы чувствуете, что вам нужно использовать указатели (сначала подумайте, действительно ли вы действительно ), вы, как правило, захотите использовать умный указатель, поскольку это может облегчить многие проблемы с необработанными указателями, в основном забывая удалить объект и утечка памяти.
При использовании необработанных указателей программист должен явно уничтожить объект, когда он больше не нужен.
// Need to create the object to achieve some goal
MyObject* ptr = new MyObject();
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?
Интеллектуальный указатель для сравнения определяет политику, когда объект уничтожается. Вам все еще нужно создать объект, но вам больше не нужно беспокоиться об его уничтожении.
SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.
// Destruction of the object happens, depending
// on the policy the smart pointer class uses.
// Destruction would happen even if DoSomething()
// raises an exception
Простейшая используемая политика включает в себя область действия объекта-оболочки интеллектуального указателя, например, реализованную с помощью boost::scoped_ptr
или std::unique_ptr
.
void f()
{
{
std::unique_ptr<MyObject> ptr(new MyObject());
ptr->DoSomethingUseful();
} // ptr goes out of scope --
// the MyObject is automatically destroyed.
// ptr->Oops(); // Compile error: "ptr" not defined
// since it is no longer in scope.
}
Обратите внимание, что std::unique_ptr
экземпляры не могут быть скопированы. Это предотвращает многократное удаление указателя (неправильно). Однако вы можете передавать ссылки на него другим вызываемым функциям.
std::unique_ptr
s полезны, когда вы хотите связать время жизни объекта с конкретным блоком кода или если вы встраивали его как данные элемента в другой объект, время жизни этого другого объекта. Объект существует до тех пор, пока не будет завершен содержащий блок кода или пока сам содержащий объект не будет уничтожен.
Более сложная политика интеллектуальных указателей включает подсчет ссылок в указателе. Это позволяет копировать указатель. Когда последняя «ссылка» на объект уничтожается, объект удаляется. Эта политика применяется boost::shared_ptr
и std::shared_ptr
.
void f()
{
typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
MyObjectPtr p1; // Empty
{
MyObjectPtr p2(new MyObject());
// There is now one "reference" to the created object
p1 = p2; // Copy the pointer.
// There are now two references to the object.
} // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero.
// The object is deleted.
Указатели с подсчетом ссылок очень полезны, когда время жизни вашего объекта намного сложнее и не привязано напрямую к определенному фрагменту кода или другому объекту.
У указателей с подсчетом ссылок есть один недостаток - возможность создания свисающей ссылки:
// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!
Другая возможность - создание циклических ссылок:
struct Owner {
std::shared_ptr<Owner> other;
};
std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1
// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!
Чтобы обойти эту проблему, Boost и C ++ 11 определили weak_ptr
, чтобы определить слабую (неисчисляемую) ссылку на shared_ptr
.
UPDATE
Этот ответ довольно старый, и поэтому описывает то, что было «хорошо» в то время, то есть умные указатели, предоставляемые библиотекой Boost. Начиная с C ++ 11, стандартная библиотека предоставляла достаточное количество типов интеллектуальных указателей, поэтому вы должны предпочесть использование std::unique_ptr
, std::shared_ptr
и std::weak_ptr
.
Существует также std::auto_ptr
. Он очень похож на указатель с ограничением, за исключением того, что он также обладает «особой» опасной способностью копироваться, что также неожиданно передает право собственности! Это устарело в новейших стандартах, поэтому вы не должны его использовать. Вместо этого используйте std::unique_ptr
.
std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership.
// p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.