c - 什么是智能指针, 而我什么时候应该使用?

  显示原文与译文双语对照的内容

什么是智能指针, 而我什么时候应该使用?

时间:

智能指针是包装'原始'( 或者'裸') C++ 指针的类,用于管理指向的对象的生命周期。 没有单一的智能指针类型,但是它们都试图以实际的方式抽象一个'原始'指针。

智能指针应该优于'原始'指针。 如果你觉得你需要使用指针( 首先考虑一下你是否真的 ),你通常会想使用智能指针,因为这可以减少'原始'指针的许多问题,主要是忘记删除对象和泄漏内存。

使用'原始'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()
{
 {
 boost::scoped_ptr<MyObject> ptr(new MyObject());
 ptr->DoSomethingUseful();
 }//boost::scopted_ptr goes out of scope -- 
//the MyObject is automatically destroyed.

//ptr->Oops();//Compile error:"ptr" not defined
//since it is no longer in scope.
}

注意 scoped_ptr 实例不能被复制。 这将防止指针多次删除( 错误的) 。 但是,你可以将对它的引用传递给你调用的其他函数。

当你想要将对象的生命周期设置为特定代码块时,或者如果你将它作为另一个对象内的成员数据嵌入到另一个对象的生命周期中,那么作用域指针很有用。 对象存在,直到包含代码块被退出,或者直到包含对象本身被销毁为止。

一个更复杂的智能指针策略涉及引用计算指针。 这确实允许复制指针。 当对象的最后一个"引用"被破坏时,对象被删除。 这里策略由 boost::shared_ptrstd::shared_ptr 实现。


void f()
{
 typedef std::tr1::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 {
 boost::shared_ptr<Owner> other;
};

boost::shared_ptr<Owner> p1 (new Owner());
boost::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!

要变通解决这里问题,既提升和C++11已经定义一个弱( uncounted ) weak_ptr 定义一个引用到一个 shared_ptr


这个答案相当古老,所以在当时使用了'好',它是由boos库提供的智能指针。 因为C++11标准库已经提供了足够的智能指针类型,因此你就应该很喜欢的使用 std::unique_ptrstd::shared_ptrstd::weak_ptr

还有 std::auto_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.

智能指针是一个具有一些附加功能的pointer-like类型,比如 自动内存释放,引用计数等。

在页面智能指针上可以使用小的介绍- 什么,为什么? 。

一个简单的smart-pointer类型是 std::auto_ptr ( 第 20.4.5章 C++ 标准),它允许自动释放内存,当抛出异常时,它比简单指针使用更健壮,但在抛出异常时比简单指针使用更灵活。

另一种方便的类型是 boost::shared_ptr,它实现引用计数并自动释放内存,当没有对对象的引用时,这有助于避免内存泄漏,这很容易用来实现自动化。

主题在 book "C++ 模板中被深度覆盖: 完整指南"由 David Vandevoorde,Nicolai M 。 Josuttis,第 20章。 智能指针。涉及的一些主题:

为 Chris,Sergdev和Llyod提供的定义是正确的。 我更喜欢一个简单的定义,只是为了保持我的生活简单: 智能指针只是一个重载 ->* 操作符的类。 这意味着你的对象语义看起来像一个指针,但你可以让它做得更酷,包括引用计数,自动销毁 等等 shared_ptrauto_ptr,在大多数情况下,它们都是足够的小特性。

大多数智能指针处理pointer-to对象的处理。 它很方便,因为你不必再手工处理对象。

大多数commonly-used智能指针都是 std::tr1::shared_ptr ( 或者 boost::shared_ptr ),而很少是 std::auto_ptr 。 我建议经常使用 shared_ptr

shared_ptr 几乎是万能的,处理各一大型的处置方案,其中包括多种情况下,对象需要被"跨越动态链接库边界"( 公共噩梦情况下如果不同 libc s 之间使用了你的代码和 DLL ) 。

智能指针类似于普通的( 类型类型) 指针,类似于"char*",除非指针本身超出了范围,然后它指向的内容也被删除。 你可以像使用普通指针一样使用它,使用"->",但如果你需要一个指向数据的实际指针。 为此,你可以使用"& *ptr"。

它对以下情况有用:

  • 必须与新的对象一起分配的对象,但你希望在堆栈上具有相同的生存期。 如果对象被分配给一个智能指针,那么当程序退出这个函数/块时它们会被删除。

  • 类的数据成员,这样当对象被删除时,所有拥有的数据都被删除,而析构函数( 你需要确保析构函数是虚拟的,这几乎是一件好事) 中没有任何特殊代码。

你可能不 希望使用一个智能指针时:

  • 。指针实际上不应该拥有数据。。 换句话说,当你正在使用数据,但你希望它在你引用它的函数中存活。
  • 智能指针不会在某些时候被破坏。 你不想让它坐在永远不会被破坏的内存中。
  • 。两个智能指针可能指向相同的数据。 ( 还有更聪明的指针可以处理这一点。) 。 这称为引用计数 。)

另请参见:

智能指针是一个类似指针的对象,但另外还提供对构造,破坏,复制,移动和取消引用的控制。

你可以实现一个智能指针,但是许多库还提供了智能指针实现,每个都有不同的优点和缺点。

例如 Boost 提供了以下智能指针实现:

  • shared_ptr<T> 是一个指向 T的指针,使用一个引用计数来确定什么时候不再需要对象。
  • scoped_ptr<T> 在超出范围时自动删除。 不可能分配。
  • intrusive_ptr<T> 是另一个引用计数指针。 它提供了比 shared_ptr 更好的性能,但要求类型 T 提供自己的引用计数机制。
  • weak_ptr<T> 是一个弱指针,与 shared_ptr 一起工作以避免循环引用。
  • shared_array<T> 就像 shared_ptr,但对于 T 数组。
  • scoped_array<T> 就像 scoped_ptr,但对于 T 数组。

这些仅仅是一个线性描述,可以根据需要使用它们,更详细的细节和示例可以查看Boost的文档。

另外,C++ 标准库提供了三个智能指针;std::unique_ptr 用于独特的所有权,std::shared_ptr 用于共享所有权和 std::weak_ptrstd::auto_ptr 已经存在于C++03中,但现在已经被否决。

下面是类似答案的链接: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

智能指针是一个行为,外观和感觉像普通指针但提供更多功能的对象。 在 C++ 中,智能指针是作为模板类实现的,它封装一个指针并覆盖标准指针运算符。 它们比常规指针有许多优势。 它们可以被初始化为空指针或者指向堆对象的指针。 通过空指针检查间接寻址。 不需要删除。 当最后一个指向它们的指针离开时,会自动释放对象。 这些智能指针的一个重要问题是,与常规指针不同,它们不尊重继承。 智能指针对于多态代码是不引人注意的。 下面给出了一个实现智能指针的示例。

示例:


template <class X>
class smart_pointer
{
 public:
 smart_pointer();//makes a null pointer
 smart_pointer(const X& x)//makes pointer to copy of x

 X& operator *( );
 const X& operator*( ) const;
 X* operator->() const;

 smart_pointer(const smart_pointer <X> &);
 const smart_pointer <X> & operator =(const smart_pointer<X>&);
 ~smart_pointer();
 private:
//...
};

此类实现一个指向类型为的对象的智能指针。 对象本身位于堆上。 下面是使用它的方法:


smart_pointer <employee> p= employee("Harris",1333);

其他重载运算符一样,p的行为类似于普通指针,


cout<<*p;
p->raise_salary(0.5);

http://en.wikipedia.org/wiki/Smart_pointer

在计算机科学中,智能指针是一种抽象数据类型,它在提供额外特性时模拟指针,比如自动垃圾收集或者边界检查。 这些额外功能是用来减少指标误用导致的错误并同时保持效率。 智能指针通常跟踪指向它们的对象以实现内存管理。 误用指针是 Bug的主要来源: 使用指针编写的程序必须执行的常数分配,释放和引用,很可能会导致某些内存泄漏发生。 智能指针通过自动释放资源来防止内存泄漏: 当指向对象( 或者是一系列指针中的最后一个)的指针被破坏时,例如因为它超出了范围,指针的对象也会被销毁。

以下是C++14最近的一个简单答案:

  • 什么是 ?
    查看 @smink's 答案
  • 我应该用一个 ?
    在其他涉及跟踪指针所有权的代码中,分配或者 de-allocating 。
  • ,但我应该使用哪种智能指针
    • 当不计划对同一对象的多个引用时使用 std::unique_ptr 。 例如对于在进入某个作用域时分配的指针和在退出作用域时的de-allocated 。
    • 当你想要从多个位置引用你的对象时使用 std::shared_ptr,并且不要让它成为 de-allocated,直到所有这些引用都消失。
    • 如果确实要引用来自多个位置的对象,请使用 std::weak_ptr 。对于那些可以忽略和释放( 所以他们会注意到当你试图取消引用时对象消失了)的引用。
    • 不要使用 boost:: 指针或者 std::auto_ptr,除非你必须在特殊情况下阅读。
  • 嘿,嘿,我没有问应该用哪一个 !
    啊,但是你真的想要,承认。
  • 我什么时候使用常规指针?
    在忽略指针所有权的代码中。 因此,通常在从其他地方获取指针而不分配的函数中,de-allocate或者存储它的执行的副本。
...