关于C++:什么是智能指针,什么时候使用?

What is a smart pointer and when should I use one?

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


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

智能指针应该优先于原始指针。如果您觉得需要使用指针(首先考虑是否确实要使用),通常您会希望使用智能指针,因为这样可以减轻原始指针的许多问题,主要是忘记删除对象和泄漏内存。

对于原始指针,程序员必须在对象不再有用时显式地销毁它。

1
2
3
4
5
// 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...?

通过比较,智能指针定义了一个策略,说明何时销毁对象。你仍然需要创建这个对象,但是你不再需要担心破坏它。

1
2
3
4
5
6
7
8
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_ptrstd::unique_ptr实现。

1
2
3
4
5
6
7
8
9
10
11
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执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
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.

当对象的生存期更为复杂,并且没有直接绑定到特定的代码部分或其他对象时,引用计数指针非常有用。

引用计数指针有一个缺点-创建悬空引用的可能性:

1
2
3
4
// 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!

另一种可能是创建循环引用:

1
2
3
4
5
6
7
8
9
10
11
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!

为了解决这个问题,Boost和C++ 11都定义了一个EDCOX1,5定义来定义一个弱的(未计数的)引用给EDCOX1 6。

更新

这个答案相当古老,所以描述了当时"好"的东西,这是Boost库提供的智能指针。自C++ 11以来,标准库已经提供了足够的智能指针类型,因此您应该支持使用EDOCX1、1、EDCOX1、4和EDCX1 9。

还有std::auto_ptr。它非常像一个作用域指针,除了它还具有"特殊"的危险复制能力——这也意外地转移了所有权!它在最新的标准中已被弃用,因此您不应该使用它。用std::unique_ptr代替。

1
2
3
4
5
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.


这是现代C++的一个简单的答案:

  • 什么是智能指针?它是一种类型,其值可以像指针一样使用,但它提供了自动内存管理的附加功能:当智能指针不再使用时,它指向的内存将被释放(另请参见维基百科上的更详细定义)。
  • 我什么时候用?在涉及跟踪一块内存的所有权、分配或取消分配的代码中,智能指针通常可以节省您显式执行这些操作的需要。
  • 但是在那些情况下,我应该使用哪个智能指针呢?
    • 当您不打算保存对同一对象的多个引用时,请使用std::unique_ptr。例如,将它用作指向内存的指针,该指针在进入某个作用域时分配,在退出作用域时取消分配。
    • 当您想从多个地方引用对象时,请使用std::shared_ptr,并且在所有这些引用都消失之前,不希望取消分配对象。
    • 当你确实想从多个地方引用你的对象时,使用std::weak_ptr——对于那些可以忽略和取消分配的引用(因此当你试图取消引用时,他们只会注意到对象已经不存在了)。
    • 不要使用boost::智能指针或std::auto_ptr,除非在特殊情况下,如果必须,您可以阅读。
  • 嘿,我没问用哪一个!啊,但你真的想承认。
  • 那么我什么时候应该使用常规指针呢?主要是在不考虑内存所有权的代码中。这通常是在从其他地方获取指针而不分配或取消分配的函数中,并且不存储执行时间超过的指针副本。


智能指针是一个指针类型与一些额外的功能,例如自动内存分配,引用计数等。

介绍了在小型智能指针是可用的页面是什么,为什么?。。。。。。。

一个简单的智能指针类型是()章std::auto_ptr20.4.5 C + +标准),它允许一个自动释放内存时,它是一个范围外,更多的鲁棒性比简单的指针使用不当而出现是不灵活的。

这是一个方便的类型boost::shared_ptr实现引用计数和自动释放内存的时候仍然没有引用的对象。这帮助避免内存泄漏和实施raii是易于使用。

在深度覆盖的主体是在图书的"C + +模板:完全指南"由大卫范德沃德,N. M. josuttis,第20章。智能指针。一些主题包括:

  • 对异常的保护
  • 持有人,(注,性病::搜索_ PTR是自动执行的智能指针类型)
  • 资源采集是初始化(这是用于异常发现的安全资源管理在C + +)
  • 持有人的限制
  • 引用计数
  • 并行计数器的访问
  • 破坏和释放


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


a智能指针是一个指针(A型)正则样,样"char *指针",但当我们看到的是什么,然后去了消去点是为好。你可以使用它像你将一个正则指针,用">",如果你不需要实际的指针的数据。那个,你可以使用"&;* ptr。

它是有用的:

  • 这是一个新的对象,必须离开,但你想有一个在那一堆东西的寿命。如果对象是由一个智能指针,然后将他们删除程序的功能是当出口/块。

  • 类的数据成员,这样,当对象是删除所有的数据是删除所有为好,没有任何特殊的代码在destructor(你需要知道destructor是虚拟的,这是几乎总是一件好事做的)。

你可能不想在使用智能指针

  • ……不应该是自己的指针的位置数据。即,当你只是使用数据,但你想在你的生存函数引用它。
  • ……智能指针本身是不是要在一些时间点。你不想坐在记忆永远不会得到的破坏(如在dynamically分配的对象不明确,但不会被删除)。
  • ……双智能指针可能同一个数据点。(这是聪明的,然而,即使你把分…这是所谓的引用计数)。

所以:湖

  • 垃圾收集。
  • 这个问题关于堆栈溢出的数据所有权

智能指针是一个类似于指针的对象,但它还提供对构造、销毁、复制、移动和取消引用的控制。

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

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

  • shared_ptr是指向T的指针,使用引用计数来确定何时不再需要对象。
  • scoped_ptr是当指针超出作用域时自动删除的指针。无法分配。
  • intrusive_ptr是另一个引用计数指针。它提供了比shared_ptr更好的性能,但需要T类型提供自己的参考计数机制。
  • weak_ptr是一个弱指针,与shared_ptr一起工作以避免循环引用。
  • shared_arrayshared_ptr相似,但用于T的数组。
  • scoped_arrayscoped_ptr相似,但用于T的数组。

这些只是每个的一个线性描述,可以根据需要使用,对于进一步的细节和示例,可以查看Boost的文档。

此外,C++标准库提供了三个智能指针;EDCOX1对14的所有权,EDOCX1,15,共享所有权和EDCOX1,16。EDCX1〔17〕存在于C++03中,但现在被弃用。


两种智能指针的指针和句柄disposing对象给你。它是非常的手机,因为你不想手动disposing对象了。

最常见的是使用智能指针(或std::tr1::shared_ptrboost::shared_ptr),和不相关的,std::auto_ptr。我推荐使用shared_ptr正则。

shared_ptr交易是非常通用的和一个大的各种处理方案,包括案例的WHERE对象需要"DLL传递跨越边界"(常用的是用不同的libcs噩梦案例如果您的代码和DLL之间)。


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

智能指针是一个动作、外观和感觉都像普通指针的对象,但提供了更多的功能。在C++中,智能指针被实现为封装指针和重写标准指针操作符的模板类。与常规指针相比,它们有许多优势。它们保证被初始化为空指针或指向堆对象的指针。检查通过空指针的间接方向。不需要删除。当指向对象的最后一个指针消失时,对象将自动释放。这些智能指针的一个重要问题是,与常规指针不同,它们不尊重继承。智能指针对于多态代码不具有吸引力。下面给出了实现智能指针的示例。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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:
               //...
};

此类实现指向X类型对象的智能指针。对象本身位于堆上。以下是如何使用它:

1
smart_pointer  p= employee("Harris",1333);

与其他重载运算符一样,p的行为类似于常规指针,

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

http:///wiki/_产生的智能指针

In computer science, a smart pointer
is an abstract data type that
simulates a pointer while providing
additional features, such as automatic
garbage collection or bounds checking.
These additional features are intended
to reduce bugs caused by the misuse of
pointers while retaining efficiency.
Smart pointers typically keep track of
the objects that point to them for the
purpose of memory management. The
misuse of pointers is a major source
of bugs: the constant allocation,
deallocation and referencing that must
be performed by a program written
using pointers makes it very likely
that some memory leaks will occur.
Smart pointers try to prevent memory
leaks by making the resource
deallocation automatic: when the
pointer to an object (or the last in a
series of pointers) is destroyed, for
example because it goes out of scope,
the pointed object is destroyed too.


让T成为本教程中的一个类C++中的指针可以分为3种类型:

1)原始指针:

1
2
T a;  
T * _ptr = &a;

它们将内存地址保存到内存中的某个位置。谨慎使用,因为程序变得复杂,难以跟踪。

带有常量数据或地址的指针向后读取

1
2
3
T a ;
const T * ptr1 = &a ;
T const * ptr1 = &a ;

指向常量数据类型t的指针。这意味着您不能使用指针更改数据类型。即*ptr1 = 19不起作用。但是你可以移动指针。如ptr1++ , ptr1--等将起作用。向后读:指向类型t的指针,它是常量

1
  T * const ptr2 ;

指向数据类型T的常量指针。这意味着您不能移动指针,但可以更改指针指向的值。也就是说,*ptr2 = 19会起作用,但ptr2++ ; ptr2--等不会起作用。向后读:指向t类型的常量指针

1
const T * const ptr3 ;

指向常量数据类型t的常量指针。这意味着既不能移动指针,也不能将数据类型指针更改为指针。IE。ptr3-- ; ptr3++ ; *ptr3 = 19;不起作用

3)智能指针:

共享指针:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  T a ;
     //shared_ptr<T> shptr(new T) ; not recommended but works
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of"
things" pointing to it.
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn();

    //
     shptr.reset() ; // frees the object pointed to be the ptr
     shptr = nullptr ; // frees the object
     shptr = make_shared<T>() ; // frees the original object and points to new object

使用引用计数来跟踪有多少"事物"指向指针指向的对象。当此计数变为0时,对象将自动删除,即当指向对象的所有共享指针超出范围时,对象将被删除。这就消除了删除使用new分配的对象的麻烦。

弱指针:帮助处理使用共享指针时出现的循环引用如果有两个共享指针指向的两个对象,并且有一个内部共享指针指向彼此的共享指针,则会有一个循环引用,当共享指针超出范围时,不会删除该对象。要解决此问题,请将内部成员从共享指针更改为弱指针。注意:要访问弱指针指向的元素,请使用lock(),这将返回弱指针。

1
2
3
4
5
6
7
T a ;
shared_ptr<T> shr = make_shared<T>() ;
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr
wk.lock()->memFn() ; // use lock to get a shared_ptr
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

看:什么时候std::weak_ptr有用?

唯一指针:轻量智能指针,拥有独家所有权。当指针指向唯一对象而不在指针之间共享对象时使用。

1
2
3
4
5
unique_ptr<T> uptr(new T);
uptr->memFn();

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr

要更改唯一指针指向的对象,请使用移动语义

1
2
3
4
5
6
unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1);
// object pointed by uptr2 is deleted and
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null

参考文献:它们本质上可以是常量指针,即一个常量指针,不能用更好的语法移动。

请参阅:C++中指针变量和引用变量之间有什么区别?

1
2
3
r-value reference : reference to a temporary object  
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified

参考文献:https://www.youtube.com/channel/uceogtxytb6vo6mq-wq9w_-nq感谢安德烈指出了这个问题。


智能指针是一个类,一个普通指针的包装器。与普通指针不同,智能点的生命周期基于引用计数(智能指针对象被分配的时间)。因此,每当智能指针分配给另一个指针时,内部引用计数加上。当对象超出范围时,引用计数减。

自动指针虽然看起来很相似,但与智能指针完全不同。当自动指针对象超出变量范围时,它是一个方便的类来释放资源。在某种程度上,它使指针(动态分配内存)的工作方式类似于堆栈变量(在编译时静态分配)。


智能指针是那些不必担心内存去分配、资源共享和传输的指针。

您可以很好地使用这些指针,类似于Java中的任何分配工作。在Java垃圾收集器中做了这个技巧,而在智能指针中,这个技巧是由析构函数完成的。


现有的答案是好的,但不包括当智能指针不是您试图解决的问题的(完整的)答案时要做什么。

除此之外(在其他答案中解释得很好),使用智能指针是如何使用抽象类作为函数返回类型的可能解决方案?已标记为此问题的副本。但是,如果想在C++中指定一个抽象的(或实际上是任何)基类作为返回类型,首先要问的问题是:"你真正的意思是什么?"在Boost指针容器库的文档中,有一个很好的讨论(进一步引用)C++中惯用的面向对象编程(以及如何与其他语言不同)。总之,在C++中,你必须考虑所有权。哪些智能指针对您有帮助,但不是唯一的解决方案,或者总是一个完整的解决方案(它们不会给您提供多态副本),并且不总是您希望在接口中公开的解决方案(函数返回听起来非常像接口)。例如,返回引用可能就足够了。但在所有这些情况下(智能指针、指针容器或简单地返回引用),您已经将返回从值更改为某种形式的引用。如果您真的需要复制,您可能需要添加更多的样板"成语",或者使用诸如Adobe Pro或BooSt.TyrRaseCube之类的库,将C++中的习惯性(或其他)OOP移至更通用的多态性。