Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.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_ptr或boost::shared_ptr,不太常见的是std::auto_ptr。我建议定期使用共享ptr

shared_ptr用途广泛,可处理多种处理方案,包括需要跨DLL边界传递对象的情况。如果在代码和DLL之间使用不同的libc,则这是一种常见的噩梦。a是一种类似指针的类型,具有一些附加功能,例如自动内存释放,参考计数等

页面上有一个小的介绍

一个简单的智能指针类型是C++标准的第20.4.5章,它允许在超出范围时自动释放内存,并且在抛出异常时比简单指针使用更健壮,虽然不灵活。 另一种方便的类型是,它实现引用计数,并在没有对对象的引用保留时自动释放内存。这有助于避免内存泄漏,并且易于使用和实现

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

防止例外情况 注意,holder就是这种类型的智能指针的实现 这在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在以下情况下非常有用 您希望将对象的生存期与特定的代码块绑定,或者如果将其作为成员数据嵌入到另一个对象中,则另一个对象的生存期。对象存在,直到包含的代码块退出,或者直到包含的对象本身被销毁

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

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

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!

为了解决这个问题,Boost和C++11都定义了一个弱ptr来定义对共享ptr的弱未计数引用。

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

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

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

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

shared_ptr是指向T的指针,使用引用计数来确定何时不再需要该对象。 scoped_ptr是一个指针,当它超出范围时会自动删除。没有任务是可能的。 介入式_ptr是另一个引用计数指针。它提供了比shared_ptr更好的性能,但要求类型T提供自己的引用计数机制。 弱\u ptr是一个弱指针,与共享\u ptr一起工作以避免循环引用。 shared_数组类似于shared_ptr,但用于T的数组。 作用域_数组类似于作用域_ptr,但适用于T的数组。 这些只是对每一个的一个线性描述,可以根据需要使用,有关更多细节和示例,可以查看Boost的文档


另外,C++标准库提供三个智能指针;std::unique_ptr表示唯一所有权,std::shared_ptr表示共享所有权,std::weak_ptr表示弱所有权。std::auto_ptr存在于C++03中,但现在已被弃用。

以下是类似答案的链接:


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

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 
例如:

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

smart_pointer <employee> p= employee("Harris",1333);
与其他重载运算符一样,p的行为类似于常规指针

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

下面是现代C++ C++ 11和以后的几天的简单答案:

什么是智能指针? 这种类型的值可以像指针一样使用,但它提供了自动内存管理的附加功能:当智能指针不再使用时,它指向的内存将被释放。另请参见。 我应该什么时候用? 在涉及跟踪一段内存的所有权、分配或取消分配的代码中;智能指针通常使您无需显式执行这些操作。 但在这些情况下,我应该使用哪种智能指针? 当您希望对象的存在时间与对其的单个所有者引用的存在时间一样长时使用。例如,将其用作指向内存的指针,该内存在进入某个作用域时分配,在退出该作用域时取消分配。 当您确实希望从多个位置引用对象,并且在所有这些引用都消失之前不希望取消分配对象时使用。 当您确实希望从多个位置引用对象时使用-对于那些可以忽略和取消分配的引用,这样当您尝试取消引用时,它们只会注意到对象已消失。 不要使用boost::smart指针或std::auto_ptr,除非在特殊情况下,您可以在必要时阅读。 嘿,我没问要用哪一个! 啊,但你真的想承认。 那么我什么时候应该使用r 那么,椭圆指针呢? 主要是在不知道内存所有权的代码中。这通常是在函数中,这些函数从其他地方获取指针,不分配也不取消分配,也不存储指针的副本,而指针的副本在执行过程中不会过期。
让T成为本教程中的一个类 C++中的指针可以分为3种类型:

1原始指针:

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

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

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;
指向作为常量的数据类型T的指针。这意味着您不能使用指针更改数据类型。ie*ptr1=19;这是行不通的。但是你可以移动指针。ie ptr1++,ptr1-;etc将起作用。 向后读取:指向类型T的指针,它是常量

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

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

3个智能指针:{include}

共享指针:

参考:
感谢Andre指出了这个问题。

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


您可以很好地使用这些指针,就像Java中的任何分配一样。在java中,垃圾收集器完成了这个技巧,而在智能指针中,这个技巧是由析构函数完成的。

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


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

现有的答案很好,但不包括当智能指针不是您试图解决的问题的完整答案时该怎么办


在其他答案中,使用智能指针可以很好地解释其他问题,其中一个可能的解决方案被标记为该问题的重复。然而,第一个问题是,如果想指定一个抽象,或者实际上,任何一个基类作为C++中的返回类型,你的意思是什么?有一个很好的讨论与进一步引用的惯用的面向对象的编程在C++中,这是如何不同于其他语言的文档中的。总之,在C++中,你必须考虑所有权。哪些智能指针可以帮助您,但不是唯一的解决方案,或者始终是一个完整的解决方案?它们不提供多态副本,也不总是希望在接口中公开的解决方案,函数返回听起来非常像接口。例如,返回一个引用就足够了。但在所有这些情况下,无论是智能指针、指针容器还是简单地返回一个引用,您都已将返回值更改为某种形式的引用。如果你真的需要拷贝,你可能需要添加更多的样板成语,或者使用C++或更一般的多态性来使用更像泛型多态性,比如使用./.p/>< p>库。什么是智能指针?< /P> 长版本,原则上:

现代C++习语:

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. 
原始指针违反RAII:当指针超出范围时,需要用户手动删除

RAII解决方案是:

Have a smart pointer class:
● Allocates the memory when initialized
● Frees the memory when destructor is called
● Allows access to underlying pointer
对于需要复制和共享的智能指针,请使用共享\u ptr:

● 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.
对于不拥有原始指针的智能指针,请使用弱\u ptr:

● not change Reference counting.
共享ptr使用:

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);
对于可能为null ptr的可选引用,请使用原始指针,这意味着:

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.

你是说std::auto_ptr p1新的MyObject;而不是std::auto_ptr p1 new Owner;?真棒的回答。如果它是为c++11更新的,那就太好了。我发现这个答案是在寻找关于新11标准的信息,如果未来的访问者能够找到更新的信息,那就太好了。我知道auto_ptr已被弃用。我相信shated_ptr和weake_ptr正如所描述的那样存在,并且我认为scoped_ptr现在在标准中是独一无二的。如果这是真的,这个答案可以更新吗?说创建一个悬挂引用的可能性是引用计数指针的一个缺点,这绝对是疯狂的。可能的悬空引用是任何C++指针的缺点。事实上,这正是智能指针想要克服的缺点
viate。如果您像示例中那样声明一个指向智能指针的指针,那么您会故意放弃智能指针的所有好处。这不是一个缺点或设计缺陷,这是可以想象的最愚蠢的用法。在访问C++11之前,我一直在pimpl模式中使用它。检查这个问题:注意,VisualStudio2005中std::auto_ptr的实现被严重破坏。使用boost参数。两篇关于这个主题的优秀文章:-这是Alexandrescu关于创建不同风格的智能指针的本质的免费章节:在他的实现中,他使用模板参数作为策略来指定他想要的属性,例如引用计数,而标准库使用单独的类。请注意,他也是在使用右值引用使std::unique\u ptr成为可能之前编写的。我想对上述问题再补充一点,智能指针std::shared\u ptr没有下标运算符,也不支持ponter算法,我们可以使用get获取内置指针。请解释为什么作用域\u ptr不像本地声明的const unique \u ptr,退出作用域时也会被删除。值得注意的是,尽管智能拥有指针有助于正确的内存管理,原始的非拥有指针对于数据结构中的其他组织用途仍然有用。赫伯·萨特(Herb Sutter)在2016年CppCon大会上就这一问题做了精彩的演讲,你可以在YouTube上看到:@wiktor.wandachowicz T*对std::unique_ptr来说就像std::weak_ptr对std::shared一样_ptr@Caleth:不,我不会这么说。警告std::auto_ptr不推荐使用,并且非常不鼓励使用,因为您可能会意外地转移所有权。-C++11不再需要Boost,使用:std::unique\u ptr、std::shared\u ptr和std::weak\u 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 
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.