什么是智能指针,何时应使用?
#1楼
在计算机科学中,智能指针是一种抽象数据类型,它在提供其他功能(例如自动垃圾收集或边界检查)的同时模拟指针。 这些附加功能旨在减少因滥用指针而导致的错误,同时保持效率。 智能指针通常会跟踪指向它们的对象,以进行内存管理。 指针的滥用是错误的主要来源:必须由使用指针编写的程序执行常量分配,释放和引用,这很可能会发生一些内存泄漏。 智能指针试图通过使资源自动分配来防止内存泄漏:当指向某个对象的指针(或一系列指针中的最后一个)被破坏时,例如,由于超出范围,指向的对象也将被破坏。
#2楼
智能指针就像常规的(类型化的)指针一样,如“ char *”,除了当指针本身超出范围时,它所指向的内容也会被删除。 您可以像使用常规指针一样使用“->”来使用它,但是如果您需要一个实际的数据指针,则不需要。 为此,您可以使用“&* ptr”。
它对:
必须分配给new的对象,但您希望拥有与该堆栈上的对象相同的生存期。 如果将对象分配给智能指针,则在程序退出该功能/块时将删除它们。
类的数据成员,以便在删除对象时也删除所有拥有的数据,而在析构函数中没有任何特殊代码(您需要确保析构函数是虚拟的,这几乎总是一件好事) 。
你可能不希望使用智能指针时:
...指针实际上不应该拥有数据...,即,当您仅使用数据时,但是您希望它在引用它的函数中存活下来。
...智能指针本身不会在某个时候被破坏。 您不希望它位于永不被破坏的内存中(例如,在动态分配但不会被明确删除的对象中)。
...两个智能指针可能指向同一数据。 (但是,还有更聪明的指针可以处理此问题……这称为引用计数 。)
也可以看看:
#3楼
大多数类型的智能指针都会为您处理指向对象的处理。 这非常方便,因为您不必再考虑手动处理对象。
最常用的智能指针是std::tr1::shared_ptr (或boost::shared_ptr ),以及std::auto_ptr 。 我建议定期使用shared_ptr 。
shared_ptr非常通用,可以处理各种处置方案,包括需要“跨越DLL边界传递对象”的情况(如果在代码和DLL之间使用不同的libc则通常是噩梦)。
#4楼
智能指针是一种类似指针的类型,具有一些其他功能,例如自动内存释放,引用计数等。
一种简单的智能指针类型是std::auto_ptr (C ++标准的20.4.5章),它允许在超出范围时自动释放内存,并且比引发异常时的简单指针使用更可靠,尽管这种情况较少灵活。
另一个方便的类型是boost::shared_ptr ,它实现引用计数并在没有剩余对对象的引用时自动释放内存。 这有助于避免内存泄漏,并且易于使用来实现RAII 。
防止异常
持有人,(请注意, std :: auto_ptr是此类智能指针的实现)
资源获取即初始化 (在C ++中经常用于异常安全的资源管理)
持有人限制
并发计数器访问
销毁和重新分配
#5楼
更新
这个答案很旧,因此描述了当时的“好”,这是Boost库提供的智能指针。 从C ++ 11开始,标准库提供了足够的智能指针类型,因此您应该赞成使用std::unique_ptr , std::shared_ptr和std::weak_ptr 。
还有std::auto_ptr 。 它非常类似于作用域指针,不同之处在于它还具有“特殊”危险功能,可被复制-还会意外地转移所有权。
它在C ++ 11中已弃用,在C ++ 17中已删除 ,因此您不应该使用它。
std::auto_ptr p1 (new MyObject());
std::auto_ptr p2 = p1; // Copy and transfer ownership.
// p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.
老答案
智能指针是包装“原始”(或“裸露”)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 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
void f()
{
{
std::unique_ptr 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则std::unique_ptr很有用。 该对象将一直存在,直到退出包含代码的块,或者直到包含对象本身被销毁为止。
更复杂的智能指针策略涉及对指针进行引用计数。 这确实允许复制指针。 当该对象的最后一个“引用”被销毁时,该对象将被删除。 该策略由boost::shared_ptr和std::shared_ptr 。
void f()
{
typedef std::shared_ptr 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 other;
};
std::shared_ptr p1 (new Owner());
std::shared_ptr 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的弱(未计数)引用。