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++中的异常安全资源管理)
- 持有人限制
- 并发计数器访问
- 销毁和解除分配
它在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.