Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么是智能指针,何时使用?_C++_Pointers_C++11_Smart Pointers_C++ Faq - Fatal编程技术网

C++ 什么是智能指针,何时使用?

C++ 什么是智能指针,何时使用?,c++,pointers,c++11,smart-pointers,c++-faq,C++,Pointers,C++11,Smart Pointers,C++ Faq,什么是智能指针?何时使用智能指针? 在计算机科学中,智能指针 是一种抽象数据类型 模拟指针,同时提供 附加功能,例如自动 垃圾收集或边界检查。 这些附加功能是预期的 减少因使用不当而导致的错误 指针,同时保持效率。 智能指针通常跟踪 指向对象的对象,用于 内存管理的目的。这个 指针的滥用是一个主要来源 错误的定义:常量分配, 取消分配和引用必须 由编写的程序执行 使用指针很可能 可能会发生一些内存泄漏。 智能指针试图阻止内存 使资源泄漏 自动解除分配:当 指向对象的指针(或 一系列指针)被销毁,

什么是智能指针?何时使用智能指针?

在计算机科学中,智能指针 是一种抽象数据类型 模拟指针,同时提供 附加功能,例如自动 垃圾收集或边界检查。 这些附加功能是预期的 减少因使用不当而导致的错误 指针,同时保持效率。 智能指针通常跟踪 指向对象的对象,用于 内存管理的目的。这个 指针的滥用是一个主要来源 错误的定义:常量分配, 取消分配和引用必须 由编写的程序执行 使用指针很可能 可能会发生一些内存泄漏。 智能指针试图阻止内存 使资源泄漏 自动解除分配:当 指向对象的指针(或 一系列指针)被销毁,例如 因为它超出了范围, 尖的物体也被破坏了


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

它有助于:

  • 必须使用new分配但希望与堆栈上的某个对象具有相同生存期的对象。如果将对象指定给智能指针,则当程序退出该函数/块时,它们将被删除

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

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

  • 。。。指针不应该实际拥有数据。。。i、 例如,当您只是在使用数据,但希望它在引用它的函数中继续存在时
  • 。。。智能指针本身不会在某个时候被破坏。您不希望它位于永远不会被破坏的内存中(例如在动态分配但不会被显式删除的对象中)
  • 。。。两个智能指针可能指向相同的数据。(然而,甚至还有更聪明的指针可以处理这个问题……这就是所谓的。)
另见:

  • 关于数据所有权

大多数类型的智能指针为您处理指向对象的指针。它非常方便,因为您不再需要考虑手动处理对象

最常用的智能指针是
std::tr1::shared\u ptr
(或
boost::shared\u ptr
),较少使用的是
std::auto\u ptr
。我建议定期使用
共享\u ptr

shared_ptr
用途广泛,可处理多种处理方案,包括需要“跨DLL边界传递对象”的情况(如果代码和DLL之间使用了不同的
libc
s,则这是常见的噩梦)。

a是一种类似指针的类型,具有一些附加功能,例如,自动内存释放、引用计数等

页面上有一个小的介绍

简单的智能指针类型之一是(C++标准的第20.4.5章),它允许在超出范围时自动释放内存,并且在抛出异常时比简单指针使用更健壮,虽然不灵活。

另一种方便的类型是,它实现引用计数,并在没有对对象的引用保留时自动释放内存。这有助于避免内存泄漏,并且易于使用和实现

本书第20章对该主题进行了深入探讨。聪明的指针。 所涵盖的一些主题:

  • 防止例外情况
  • 保持架,(注意,是此类智能指针的实现)
  • (这经常用于C++中的异常安全资源管理)
  • 持有人限制
  • 并发计数器访问
  • 销毁和解除分配

更新

这个答案相当古老,因此描述了什么是“好的”,这是Boost库提供的智能指针。自C++11以来,标准库提供了足够多的智能指针类型,因此您应该支持使用、和

还有。它与作用域指针非常相似,只是它还具有“特殊”的危险复制能力,这也意外地转移了所有权。
它在C++11中被弃用,在C++17中被删除,因此您不应该使用它

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.
通过比较,智能指针定义了一个关于何时销毁对象的策略。您仍然需要创建对象,但不必再担心会破坏它

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
请注意,无法复制
std::unique_ptr
实例。这样可以防止多次(错误地)删除指针。但是,您可以将对它的引用传递给您调用的其他函数

std::unique_ptr
s在您希望将对象的生存期绑定到特定的代码块时非常有用,或者如果您将其作为成员数据嵌入到另一个对象中,则另一个对象的生存期。对象存在,直到包含的代码块退出,或者直到包含的对象本身被销毁

更复杂的智能指针策略涉及指针的引用计数。这允许复制指针。当对象的最后一个“引用”被销毁时,该对象将被删除。本政策由和执行

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

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!
结构所有者{ std::共享的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.
}
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!
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);
cout<<*p;
p->raise_salary(0.5);
T a;  
T * _ptr = &a; 
T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;
  T * const ptr2 ;
const T * const ptr3 ; 
  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
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
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 
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 
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 
RAII: Resource Acquisition Is Initialization.

● When you initialize an object, it should already have 
  acquired any resources it needs (in the constructor).


● When an object goes out of scope, it should release every 
  resource it is using (using the destructor).
● There should never be a half-ready or half-dead object.
● When an object is created, it should be in a ready state.
● When an object goes out of scope, it should release its resources. 
● The user shouldn’t have to do anything more. 
Have a smart pointer class:
● Allocates the memory when initialized
● Frees the memory when destructor is called
● Allows access to underlying pointer
● use another memory to store Reference counting and shared.
● increment when copy, decrement when destructor.
● delete memory when Reference counting is 0. 
  also delete memory that store Reference counting.
● not change Reference counting.
correct way:
std::shared_ptr<T> t1 = std::make_shared<T>(TArgs);
std::shared_ptr<T> t2 = std::shared_ptr<T>(new T(Targs));

wrong way:
T* pt = new T(TArgs); // never exposure the raw pointer
shared_ptr<T> t1 = shared_ptr<T>(pt);
shared_ptr<T> t2 = shared_ptr<T>(pt);
not use T*
use T&  
T* pt; is optional reference and maybe nullptr.
Not own the raw pointer, 
Raw pointer is managed by some one else.
I only know that the caller is sure it is not released now.