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


当前回答

智能指针类似于常规(类型化)指针,如“char*”,除非指针本身超出范围,否则它所指向的内容也会被删除。您可以像使用常规指针一样使用它,方法是使用“->”,但如果您需要指向数据的实际指针,则不需要。为此,可以使用“&*ptr”。

它适用于:

对象必须分配新的,但您希望与堆栈中的对象具有相同的生存期。如果对象被分配给智能指针,那么当程序退出该函数/块时,它们将被删除。类的数据成员,因此当对象被删除时,所有拥有的数据也会被删除,而析构函数中没有任何特殊代码(您需要确保析构函数是虚拟的,这几乎总是一件好事)。

在以下情况下,您可能不想使用智能指针:

…指针实际上不应该拥有数据。。。即,当您只是在使用数据,但希望它在引用它的函数中生存时。…智能指针本身不会在某个时刻被破坏。您不希望它位于永远不会被破坏的内存中(例如动态分配但不会显式删除的对象中)。…两个智能指针可能指向相同的数据。(然而,还有更聪明的指针可以处理这一点……这就是所谓的引用计数。)

另请参见:

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

其他回答

以下是类似答案的链接: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:
               //...
};

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

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

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

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

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

在计算机科学中,智能指针是一种抽象数据类型模拟指针,同时提供其他功能,如自动垃圾收集或边界检查。这些附加功能旨在减少因误用指针,同时保持效率。智能指针通常跟踪指向它们的对象内存管理的目的。这个指针的误用是一个主要原因错误:恒定分配,释放和引用由编写的程序执行使用指针很可能会发生一些内存泄漏。智能指针试图阻止内存通过制造资源泄漏自动解除分配:当指向对象的指针(或一系列指针)被破坏例如,因为它超出了范围,指向的对象也被破坏。

智能指针类似于常规(类型化)指针,如“char*”,除非指针本身超出范围,否则它所指向的内容也会被删除。您可以像使用常规指针一样使用它,方法是使用“->”,但如果您需要指向数据的实际指针,则不需要。为此,可以使用“&*ptr”。

它适用于:

对象必须分配新的,但您希望与堆栈中的对象具有相同的生存期。如果对象被分配给智能指针,那么当程序退出该函数/块时,它们将被删除。类的数据成员,因此当对象被删除时,所有拥有的数据也会被删除,而析构函数中没有任何特殊代码(您需要确保析构函数是虚拟的,这几乎总是一件好事)。

在以下情况下,您可能不想使用智能指针:

…指针实际上不应该拥有数据。。。即,当您只是在使用数据,但希望它在引用它的函数中生存时。…智能指针本身不会在某个时刻被破坏。您不希望它位于永远不会被破坏的内存中(例如动态分配但不会显式删除的对象中)。…两个智能指针可能指向相同的数据。(然而,还有更聪明的指针可以处理这一点……这就是所谓的引用计数。)

另请参见:

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

下面是现代C++(C++11及更高版本)的一个简单答案:

“什么是智能指针?”这是一种类型,其值可以像指针一样使用,但它提供了自动内存管理的附加功能:当智能指针不再使用时,它指向的内存将被释放(另请参阅维基百科上更详细的定义)。“我什么时候该用?”在涉及跟踪内存所有权、分配或取消分配的代码中;智能指针通常不需要显式地执行这些操作。“但在这些情况下,我应该使用哪个智能指针?”当您希望对象的生存时间与对它的单个拥有引用的生存时间一样长时,请使用std::unique_ptr。例如,将它用作指向内存的指针,该指针在进入某个作用域时分配,在退出作用域时取消分配。当您确实希望从多个位置引用对象时,请使用std::shared_ptr,并且不希望在所有这些引用都消失之前取消分配对象。当您确实希望从多个位置引用对象时,请使用std::weak_ptr-对于那些可以忽略和取消分配的引用(因此当您尝试取消引用时,它们会注意到对象已消失)。有人建议在C++26中添加危险指针,但目前还没有。不要使用boost::smart指针或std::auto_ptr,除非在特殊情况下,您可以在必要时阅读。“嘿,我没问该用哪一个!”啊,但你真的想承认。“那么,我什么时候应该使用常规指针?”大部分代码都忽略了内存所有权。这通常发生在从其他地方获取指针的函数中,它们既不分配也不取消分配,也不存储指针的副本,该副本的执行时间会延长。

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

1) 原始指针:

T a;  
T * _ptr = &a; 

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

具有常量数据或地址的指针{向后读取}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

指向作为常量的数据类型T的指针。这意味着不能使用指针更改数据类型。ie*ptr1=19;不会起作用。但是你可以移动指针。即ptr1++、ptr1--;等等都会起作用。向后读取:指向类型T(常量)的指针

  T * const ptr2 ;

指向数据类型T的常量指针。这意味着不能移动指针,但可以更改指针指向的值。ie*ptr2=19将工作,但ptr2++;ptr2等将不起作用。向后读取:指向T类型的常量指针

const T * const ptr3 ; 

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

3) 智能指针:{#include<memory>}

共享指针:

  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时,对象将自动删除,即当指向对象的所有share_ptr超出范围时,对象被删除。这消除了必须删除使用new分配的对象的麻烦。

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

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何时有用?

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

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 

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

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++中指针变量和引用变量之间的区别是什么?

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 感谢安德烈指出了这个问题。