C++ smart pointer

smart pointer是什么

In computer science, a smart pointer is an abstract data type that simulates a pointer while providing added features, such as automatic memory management or bounds checking.

是个抽象的数据类型,模拟指针的行为同时提供附加的features: 比如自动memory管理或边界检查


Such features are intended to reduce bugs caused by the misuse of pointers, while retaining efficiency. Smart pointers typically keep track of the memory they point to,
and may also be used to manage other resources, such as network connections and file handles. Smart pointers were first popularized in the programming language C++
during the first half of the 1990s as rebuttal to criticisms of C++'s lack of automatic garbage collection.

smart pointer用于减少指针误用引入的bug. smart pointer一般用于memory跟踪,也可用于管理其他资源如网络连接和文件句柄等。smart pointer 首先在c++中流行以用于反击对c++缺少自动垃圾回收。

Pointer misuse can be a major source of bugs. Smart pointers prevent most situations of memory leaks by making the memory deallocation automatic. More generally,
they make object destruction automatic: an object controlled by a smart pointer is automatically destroyed (finalized and then deallocated)
when the last (or only) owner of an object is destroyed, for example because the owner is a local variable, and execution leaves the variable's scope.
Smart pointers also eliminate  pointers by postponing destruction until an object is no longer in use.

解决如下问题:1]防止内存泄露(一直不释放内存),2]当使用时内存已释放

If a language supports automatic garbage collection (for example, Java or C#), then smart pointers are unneeded for the reclaiming and safety aspects of memory management,
yet are useful for other purposes, such as cache data structure residence management and resource management of objects such as file handles or network sockets.

对支持自动垃圾回收的语言,smart pointer有什么用途?

smart pointer 类型

Several types of smart pointers exist. Some work with reference counting, others by assigning ownership of an object to one pointer.

利用引用计数(多个client去使用),控制执行对象的所有权

smart pointer的 C++实现

In C++, a smart pointer is implemented as a template class that mimics, by means of operator overloading, the behaviors of a traditional (raw) pointer, (e.g. dereferencing, assignment) while providing additional memory management features.

smart pointer 实现为模板类,通过运算符重载,模仿指针的行为如接引用,赋值等同时提供另外的内存管理功能

Smart pointers can facilitate intentional programming by expressing, in the type, how the memory of the referent of the pointer will be managed.

smart pointer能通过其类型表达怎样管理memory,如下面的例子


For example, if a C++ function returns a pointer, there is no way to know whether the caller should delete the memory of the referent
when the caller is finished with the information.

SomeType* AmbiguousFunction();  // What should be done with the result?


C++11 introduced a way to ensure correct memory management in this case by declaring the function to return a unique_ptr,std::unique_ptr<SomeType> ObviousFunction();


The declaration of the function return type as a unique_ptr makes explicit the fact that the caller takes ownership of the result, and the C++ runtime ensures that the memory will be reclaimed automatically.

unique_ptr

C++11 introduces std::unique_ptr, defined in the header <memory>

A unique_ptr is a container for a raw pointer, which the unique_ptr is said to own.
A unique_ptr explicitly prevents copying of its contained pointer (as would happen with normal assignment), but the std::move function can be used to transfer ownership of the contained pointer to another unique_ptr.
A unique_ptr cannot be copied because its copy constructor and assignment operators are explicitly deleted.

unique_ptr是raw pointer的容器,unique_ptr明确禁止了copy 操作,也就是只能由一个unique_ptr管理raw pointer, 但可以使用move操作转移所有权。

std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1;  // Compile error.
std::unique_ptr<int> p3 = std::move(p1);  // Transfers ownership. p3 now owns the memory and p1 is set to nullptr.

p3.reset();  // Deletes the memory.
p1.reset();  // Does nothing.

shared_ptr and weak_ptr


C++11 introduces std::shared_ptr and std::weak_ptr, defined in the header <memory>.
C++11 also introduces std::make_shared (std::make_unique was introduced in C++14) to safely allocate dynamic memory in the RAII paradigm.

A shared_ptr is a container for a raw pointer. It maintains reference counting ownership of its contained pointer in cooperation with all copies of the shared_ptr.

shared_ptr 维护引用计数,通过赋值shared_ptr增加引用计数。


An object referenced by the contained raw pointer will be destroyed when and only when all copies of the shared_ptr have been destroyed.

std::shared_ptr<int> p0(new int(5));  // Valid, allocates 1 integer and initialize it with value 5.
std::shared_ptr<int[]> p1(new int[5]);  // Valid, allocates 5 integers.
std::shared_ptr<int[]> p2 = p1;  // Both now own the memory.

p1.reset();  // Memory still exists, due to p2. reset()操作减少引用计数
p2.reset();  // Frees the memory, since no one else owns the memory.

怎样创建weak_ptr? It is created as a copy of a shared_ptr.
A weak_ptr is a container for a raw pointer. It is created as a copy of a shared_ptr.
The existence or destruction of weak_ptr copies of a shared_ptr have no effect on the shared_ptr or its other copies. (弱引用的创建或析构都不影响shared_ptr)
After all copies of a shared_ptr have been destroyed, all weak_ptr copies become empty.(当所有的shared_ptr引用都析构了,weak_ptr所有引用都变成了空)

std::shared_ptr<int> p1 = std::make_shared<int>(5);
std::weak_ptr<int> wp1 {p1};  // p1 owns the memory.

{
  std::shared_ptr<int> p2 = wp1.lock();  // Now p1 and p2 own the memory.
  // p2 is initialized from a weak pointer, so you have to check if the
  // memory still exists!

  if (p2) {
    DoSomethingWith(p2);
  }
}
// p2 is destroyed. Memory is owned by p1.

p1.reset();  // Free the memory.

std::shared_ptr<int> p3 = wp1.lock();
// Memory is gone, so we get an empty shared_ptr.
if (p3) {  // code will not execute
  ActionThatNeedsALivePointer(p3);
}

Dangling pointer and wild pointer

Dangling pointers and wild pointers in computer programming are pointers that do not point to a valid object of the appropriate type. These are special cases of memory safety violations.

悬空指针和野指针是没有指向有效对象的指针

Dangling pointer

Dangling pointers arise during object destruction, when an object that has an incoming reference is deleted or deallocated, without modifying the value of the pointer, so that the pointer still points to the memory location of the deallocated memory.

悬空指针发生在对象析构,但指向该对象的引用或指针的值没有被修改还是指向释放的地址

The system may reallocate the previously freed memory, and if the program then dereferences the (now) dangling pointer, unpredictable behavior may result, as the memory may now contain completely different data.

系统可能重新分配了释放的memory, 如果仍然使用原来的引用/指针(当前已经是悬空指针),会发生各种异常。

If the program writes to memory referenced by a dangling pointer, a silent corruption of unrelated data may result, leading to subtle bugs that can be extremely difficult to find.

如果是内存分配给另一个进程,linux发生段错误。

If the memory has been reallocated to another process, then attempting to dereference the dangling pointer can cause segmentation faults (UNIX, Linux) or general protection faults (Windows).

如果有足够的权限写任意地址,会导致系统稳定性

If the program has sufficient privileges to allow it to overwrite the bookkeeping data used by the kernel's memory allocator, the corruption can cause system instabilities.

有垃圾回收的语言,可以避免 dangling pointer

In object-oriented languages with garbage collection, dangling references are prevented by only destroying objects that are unreachable, meaning they do not have any incoming pointers; this is ensured either by tracing or reference counting.

Wild pointer

野指针说的是使用前没有被赋值

Wild pointers arise when a pointer is used prior to initialization to some known state, which is possible in some programming languages. They show the same erratic behavior as dangling pointers, though they are less likely to stay undetected because many compilers will raise a warning at compile time if declared variables are accessed before being initialized.

为什么需要弱引用?不会造成死锁?什么情景使用弱引用?

智能指针一个很重要的概念是“所有权”,所有权意味着当这个智能指针被销毁的时候,它指向的内存(或其它资源)也要一并销毁。这技术可以利用智能指针的生命周期,来自动地处理程序员自己分配的内存,避免显示地调用delete,是自动资源管理的一种重要实现方式。

为什么要引入“弱引用”指针呢?弱引用指针就是没有“所有权”的指针。有时候我只是想找个指向这块内存的指针,但我不想把这块内存的生命周期与这个指针关联。这种情况下,弱引用指针就代表“我指向这东西,但这东西什么时候释放不关我事儿……”

有些地方为了方便,直接用原始指针(raw pointer)来表示弱引用。然后用这种原始指针,其弱引用的含义不够明确,万一别人写个delete xxxx,你就被坑了……而且弱引用指针还有其它一些方便你正确使用它的好处。

cache use case 使用弱引用

For recently accessed objects, you want to keep them in memory, so you hold a strong pointer to them. Periodically, you scan the cache and decide which objects have not been accessed recently. You don't need to keep those in memory, so you get rid of the strong pointer.

But what if that object is in use and some other code holds a strong pointer to it? If the cache gets rid of its only pointer to the object, it can never find it again. So the cache keeps a weak pointer to objects that it needs to find if they happen to stay in memory.

This is exactly what a weak pointer does -- it allows you to locate an object if it's still around, but doesn't keep it around if nothing else needs it.

弱引用使用方法

std::shared_ptr<int> p1 = std::make_shared<int>(5);
std::weak_ptr<int> wp1 {p1};  // p1 owns the memory.

{

  //升级为强引用,但可能失败,但一旦升级成功就得到了强引用
  std::shared_ptr<int> p2 = wp1.lock();  // Now p1 and p2 own the memory.
  // p2 is initialized from a weak pointer, so you have to check if the
  // memory still exists!

  if (p2) {
    DoSomethingWith(p2);
  }
}

Suppose you have Team and Member objects.

Obviously it's a relationship : the Team object will have pointers to its Members. And it's likely that the members will also have a back pointer to their Team object.

Then you have a dependency cycle. If you use shared_ptr, objects will no longer be automatically freed when you abandon reference on them, because they reference each other in a cyclic way. This is a memory leak.

You break this by using weak_ptr. The "owner" typically use shared_ptr and the "owned" use a weak_ptr to its parent, and convert it temporarily to shared_ptr when it needs access to its parent.(也就是上面说的弱引用使用方法)

Smart pointer 使用方法

Smart Pointers in C++ and How to Use Them - GeeksforGeeksA Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.https://www.geeksforgeeks.org/smart-pointers-cpp/

Smart pointer 实现原理 

// A generic smart pointer class

template <class T>

class SmartPtr {

    T* ptr; // Actual pointer

public:

    // Constructor

    explicit SmartPtr(T* p = NULL) { ptr = p; }

    // Destructor

    ~SmartPtr() { delete (ptr); }

    // Overloading dereferncing operator

    T& operator*() { return *ptr; }

    // Overloading arrow operator so that

    // members of T can be accessed

    // like a pointer (useful if T represents

    // a class or struct or union type)

    T* operator->() { return ptr; }

};

std::move()

C++11中std:move()的作用和用法_grf123的专栏-CSDN博客_c++ move()官方文档:http://www.cplusplus.com/reference/utility/move/?kw=move功能:返回传入参数的右值引用。右值引用的概念是在C++11才提出来的。在此之前只有一种引用。优点:调用此函数不会引起任何数据争用。(Calling this function introduces no data races.)看例子代码:// move ex...https://blog.csdn.net/grf123/article/details/105379337/move - C++ Referencehttp://www.cplusplus.com/reference/utility/move/?kw=move

      //临时变量都 move到全局变量

      std::vector<int> variables;
      for (int i = 0; i < modified_subgraph->tensors_size(); ++i) {
        auto* tensor = modified_subgraph->tensor(i);
        if (tensor->is_variable) {
          variables.push_back(i);
        }   
      }   
      modified_subgraph->SetVariables(std::move(variables));
    }   

  TfLiteStatus InterpreterBuilder::ApplyDelegates(Interpreter* interpreter,
                                                  int num_threads) {
    // Apply Flex delegate if applicable.
    if (has_flex_op_) {
      if (auto flex_delegate = AcquireFlexDelegate()) {
        return interpreter->ModifyGraphWithDelegate(std::move(flex_delegate));
      }
    }
  
    return kTfLiteOk;
  } 

对象(smart pointer)建立在栈上,由作用域控制对象的生命周期,也就是自动调用析构函数

对象(smart pointer)建立在堆上,就要自动析构对象了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智能指针是C++中用于管理动态分配的内存的一种机制。它们可以自动地在不再需要时释放内存,从而避免内存泄漏和悬挂指针的问题。 shared_ptr是一种引用计数智能指针,它可以跟踪有多少个shared_ptr指向同一个对象,并在没有引用时自动释放内存。当创建shared_ptr时,它会增加引用计数,当销毁或重置shared_ptr时,它会减少引用计数。只有当引用计数为0时,才会真正释放内存。\[1\]shared_ptr可以通过构造函数接受一个指向动态分配对象的指针来创建,也可以使用std::make_shared函数来创建。\[2\] unique_ptr是一种独占智能指针,它拥有对动态分配对象的唯一所有权。当unique_ptr被销毁时,它会自动释放内存。unique_ptr不能被复制,但可以通过std::move函数进行转移所有权。\[3\]unique_ptr可以通过构造函数接受一个指向动态分配对象的指针来创建。 weak_ptr是一种弱引用智能指针,它指向由shared_ptr管理的对象,但不会增加引用计数。weak_ptr可以用于解决shared_ptr的循环引用问题,因为它不会导致对象无法释放。\[1\]weak_ptr可以通过shared_ptr的构造函数来创建。 auto_ptr是C++11之前的一种智能指针,它类似于unique_ptr,但有一些限制和问题。auto_ptr在复制时会转移所有权,这可能导致悬挂指针的问题。因此,auto_ptr已经被unique_ptr取代,不推荐使用。 总结来说,shared_ptr是引用计数智能指针,unique_ptr是独占智能指针,weak_ptr是弱引用智能指针,而auto_ptr是已经过时的智能指针。它们各自有不同的用途和特点,可以根据具体的需求选择使用。 #### 引用[.reference_title] - *1* *2* *3* [C++11 解决内存泄露问题的智能指针:shared_ptr、unique_ptr、weak_ptr](https://blog.csdn.net/weixin_44120785/article/details/128714630)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值