C++智能指針使用指南 part1:基本使用

加粗樣式>@TOC

智能指針是代理模式的具體應用,它使用 RAII 技術代理了裸指針,能夠自動釋放內存, 無需程序員干預,所以被稱為“智能指針”。

智能指針不是指針,而是一個對象,所以不要對其調用delete,它會自動管理初始化時的指針,在離開作用域時析構釋放內存。

智能指針也沒有定義加減運算,不能隨意移動指針地址,這樣避免了指針越界操作。

在使用上:

如果指針是“獨占”使用,就應該選擇 unique_ptr,它為裸指針添加了很多限制,更加安全 。

如果指針是“共享”使用,就應該選擇 shared_ptr,它的功能非常完善,用法幾乎與原始指針一樣

使用智能指針要加頭文件#include <memory>

工廠函數make_unique()、make_shared()不只是返回智能指針對象,其內部也有優化。

如果你已經理解了智能指針,就盡量不要再使用裸指針、new 和 delete 來操作內存了。

unique_ptr

unique_ptr需要手動初始化,聲明的時候必須用模板參數指定類型:

unique_ptr<int> ptr1(new int(10)); // int智能指針
assert(*ptr1 = 10); // 可以使用*取內容
assert(ptr1 != nullptr); // 可以判斷是否為空指針
unique_ptr<string> ptr2(new string("hello")); // string智能指針
assert(*ptr2 == "hello"); // 可以使用*取內容
assert(ptr2->size() == 5); // 可以使用->調用成員函數

也可以調用工廠函數,強制創建智能指針的時候必須初始化:

auto ptr3 = make_unique<int>(42); // 工廠函數創建智能指針
assert(ptr3 && *ptr3 == 42);
auto ptr4 = make_unique<string>("god of war"); // 工廠函數創建智能指針
assert(!ptr4->empty());

unique_ptr表示該智能指針的所有權是唯一的,不允許共享,任何時候只能有一個人持有。

它禁止拷貝賦值,但是可以使用std::move()顯式地聲明所有權轉移:

auto ptr1 = make_unique<int>(42); // 工廠函數創建智能指針
assert(ptr1 && *ptr1 == 42); // 此時智能指針有效
auto ptr2 = ptr1; // 編譯有問題
auto ptr2 = std::move(ptr1); // 使用move()轉移所有權
assert(ptr2 && *ptr2 == 42);
assert(ptr1); // 此時智能指針無效.會報錯

指針的所有權就被轉走了,原來的 unique_ptr 變成了空指針,新的 unique_ptr 接替了管理權,保證所有權的唯一性

shared_ptr

基本使用方式與unique_ptr并無不同:

shared_ptr<int> ptr1(new int(10)); // int智能指針
assert(*ptr1 = 10); // 可以使用*取內容
shared_ptr<string> ptr2(new string("hello")); // string智能指針
assert(*ptr2 == "hello"); // 可以使用*取內容
auto ptr3 = make_shared<int>(42); // 工廠函數創建智能指針
assert(ptr3 && *ptr3 == 42); // 可以判斷是否為空指針
auto ptr4 = make_shared<string>("zelda"); // 工廠函數創建智能指針
assert(!ptr4->empty()); // 可以使用->調用成員函數

不過它的所有權可以被安全共享,支持拷貝賦值

auto ptr1 = make_shared<int>(42); // 工廠函數創建智能指針
assert(ptr1 && ptr1.unique() ); // 此時智能指針有效且唯一
auto ptr2 = ptr1; // 直接拷貝賦值,不需要使用move()
assert(ptr1 && ptr2); // 此時兩個智能指針均有效
assert(ptr1 == ptr2); // shared_ptr可以直接比較
// 兩個智能指針均不唯一,且引用計數為2
assert(!ptr1.unique() && ptr1.use_count() == 2);
assert(!ptr2.unique() && ptr2.use_count() == 2);

其內部使用引用計數,所以具有完整的”值語義“,可以在任何場合下代替原始指針。

不過維護引用計數的存儲和管理都是成本,過度使用會降低運行效率。其引用計數也會帶來循環引用,下面是簡化后的典型例子:

#include <iostream>
#include <memory>
#include <assert.h>
using namespace std;
class Node final {
public:using this_type = Node;using shared_type = std::shared_ptr<this_type>;shared_type next;   // 使用只能指針來指向下一個節點
};
int main() {auto n1 = make_shared<Node>();  // 工廠函數創建智能指針auto n2 = make_shared<Node>();// 此時引用計數均為1assert(n1.use_count() == 1);assert(n2.use_count() == 1);// 產生循環引用n1->next = n2;n2->next = n1;// 此時引用計數均為2,且無法減到0,內存泄露assert(n1.use_count() == 2);assert(n2.use_count() == 2);
}

這個例子很簡單,你一下子就能看出存在循環引用。但在實際開發中,指針的關系可不像例 子那么清晰,很有可能會不知不覺形成一個鏈條很長的循環引用,復雜到你根本無法識別, 想要找出來基本上是不可能的。 想要從根本上杜絕循環引用,光靠 shared_ptr 是不行了,必須要用到weak_ptr

weak_ptr

它專門為打破循環引用而設計,只觀察指針,不會增 加引用計數(弱引用),但在需要的時候,可以調用成員函數 lock(),獲取 shared_ptr(強引用) 。用法如下

#include <iostream>
#include <memory>
#include <assert.h>
using namespace std;
class Node final {
public:using this_type = Node;// 改用weak_ptrusing shared_type = std::weak_ptr<this_type>;shared_type next;   // 使用只能指針來指向下一個節點
};
int main() {auto n1 = make_shared<Node>();  // 工廠函數創建智能指針auto n2 = make_shared<Node>();// 此時引用計數均為1assert(n1.use_count() == 1);assert(n2.use_count() == 1);// 產生循環引用n1->next = n2;n2->next = n1;// 因為使用了weak_ptr,引用計數為1assert(n1.use_count() == 1);assert(n2.use_count() == 1);if (!n1->next.expired()) {  // 檢查指針是否有效auto ptr = n1->next.lock(); // lock()獲取shared_ptrassert(ptr == n2);}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/376878.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/376878.shtml
英文地址,請注明出處:http://en.pswp.cn/news/376878.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AS3.0 BitmapData類介紹

注&#xff1a;文中的Bitmapdata和BMD均為同一意思BitmapData,BMD為其縮寫一&#xff0c;概括&#xff1a; Bitmapdata繼承Object對象&#xff0c;實現IBitmapDrawable接口&#xff0c;這個接口有什么用&#xff0c;你可以理解為Drawable,能被畫。官方介紹是&#xff1a;IBitma…

C++使用JSON的序列化與反序列化

這里使用的json解析工具為JSON for Modern C,使用的話僅需要包含頭文件。 獲取方式&#xff1a;wget https://github.com/nlohmann/json/releases/download/v3.7.3/json.hpp JSON json的序列化功能和map一樣&#xff0c;用關聯數組的"[]"來任意添加數據&#xff0c…

iOS判斷為空或者只為空格

本文轉載至 &#xff1a;http://www.cnblogs.com/superhappy/archive/2012/11/08/2761403.html 經常有需求 要判斷不能為空&#xff0c;后臺老是鄙視不做非空判斷的前端 &#xff0c;木辦法 只能寫一個。 第一種想法&#xff1a;我不就是判斷 是不是nil就可以了么。結果發現太天…

Hyper-V

Hyper-V&#xff1a;也就是虛擬化技術&#xff0c;允許終端用戶在同一臺機器上運行多個操作系統&#xff0c;支持32位和64位系統&#xff0c;可以直接在Windows 8上創建自己的虛擬機。開啟Hyper-V虛擬機需要更多的內存&#xff0c;正常運行需要至少4GB以上內存&#xff0c;所以…

sdut 1451 括號東東 DP

http://acm.sdut.edu.cn/sdutoj/problem.php?actionshowproblem&problemid1451 題意&#xff1a;中文..... 思路&#xff1a; pku有一道題&#xff0c;經典的括號匹配&#xff08;區間DP&#xff09;題目&#xff0c;那道題目是求的最長滿足條件的子串的長度&#xff0c;那…

CDN緩存替代算法

CDN緩存工作過程如下&#xff1a;用戶發出一個請求&#xff0c;如果請求被命中&#xff0c;緩存將對用戶的請求進行響應&#xff0c;返回其請求的數據&#xff1b;如果未被命中&#xff0c;緩存向上拉取用戶需要的數據&#xff0c;并對其存儲的數據進行替換。 緩存算法的意義在…

前端開發常用正則表達式

1、電話 var phone /(^[^1][0-9\-]{6,20}$)|(^(134|135|136|137|138|139|150|151|152|157|158|159|182|183|187|188|147|130|131|132|155|156|185|186|145|133|153|180|189|181|184)\d{8}$)/ 2、郵箱 var email /^([a-zA-Z0-9_.-])([a-zA-Z0-9_-])((\.[a-zA-Z0-9_-]{2,3}){1,…

android 中調用接口發送短信

轉載&#xff1a;http://ziyu-1.iteye.com/blog/1013932 android中可以通過兩種方式發送短信 第一&#xff1a;調用系統短信接口直接發送短信&#xff1b;主要代碼如下&#xff1a; Java代碼//直接調用短信接口發短信 SmsManager smsManager SmsManager.getDefault(); List…

linux 命令案例學習——文件搜索

兩個搜索文件的工具 locate ——僅僅通過文件名查找文件find ——依據文件的各種屬性在既定目錄&#xff08;包括子目錄&#xff09;里查找一個通常與文件搜索命令一起使用、處理搜索結果文件列表的命令 xargs1 locate 1.1 查找文件名中含有zip的文件名 locate zip 看下結…

Redis 緩存擊穿、緩存穿透、緩存雪崩的處理方法

常用的分布式緩存Redis單機并發量能達到萬級&#xff0c;常用的關系型數據庫MySQL一般并發量是千級&#xff0c;他們支持的并發量可能差十倍&#xff0c;所以要盡可能把流量攔截在緩存層。 緩存擊穿 一個并發訪問量比較大的key在某個時間過期&#xff0c;導致所有的請求直接打…

Java-- 異常與記錄日志

可以使用java.util.logging工具將輸出記錄在日志中。記錄日志的的功能還是很簡單的&#xff0c;下面直接鋪出代碼&#xff1a; 1 package com.exceptions;2 3 import java.io.*;4 import java.util.logging.Logger;5 6 class LoggingException extends Exception{7 private…

圖像處理基礎

圖像處理基礎 在計算機中&#xff0c;按照顏色和灰度的多少可以將圖像分為二值圖像、灰度圖像、索引圖像和真彩色RGB圖像四種基本類型。目前&#xff0c;大多數圖像處理軟件都支持這四種類型的圖像。 (1) 二值圖像&#xff1a;一幅二值圖像的二維矩陣僅由0、1兩個值構成&#x…

緩存一致性解決方法

對于緩存 數據庫讀寫&#xff0c;有個經典的Cache Aside Pattern&#xff1a; 讀取&#xff1a;先讀取緩存&#xff0c;緩存里沒有&#xff0c;讀取數據庫&#xff0c;然后返回響應&#xff0c;順便保存緩存&#xff1a; 更新&#xff1a;先更新數據庫&#xff0c;然后刪除緩…

使用SpringMVC的表單驗證

上一篇搭建了基本項目&#xff0c;這一篇在此基礎上加入表單驗證功能。 第一步&#xff0c;添加command類 Java代碼 package test.bean; import javax.validation.constraints.Size; public class User { Size(min3,max30) private String username; …

hdu1247(Hat’s Words)

我以為像a、aa這樣的輸入應該是沒有輸出的&#xff0c;結果還是要輸出aa。 建樹的時候就是常規建樹&#xff0c;不過查找的時候要做一些變形&#xff1a;對于一個單詞&#xff0c;從第一位檢查有沒有單詞是它的前綴&#xff0c;如果有的話&#xff0c;再去檢查它的后半部分是不…

單體、分布式、微服務、Serverless軟件架構一覽

目錄軟件架構單體架構分布式應用微服務架構Serverless架構總結Reference軟件架構 軟件架構就是軟件的基本結構&#xff0c;合適的架構是軟件成功的最重要因素之一。這里列舉了目前流行的4種軟件架構。 單體架構 典型的三級架構&#xff1a;前端&#xff08;web/手機端&#…

MyBatis3 association error - The content of element type resultMap must match (constructor?,id*,r...

MyBatis3 association error - The content of element type "resultMap" must match "(constructor?,id*,result*,association*,collection*,discriminator?)" 1.后臺錯誤信息-問題現象&#xff1a; ERROR [geby:Context initialization failed] 2013-0…

Midjourney V6刷屏,但它最可怕的地方居然不是那些神圖?

Midjourney在沉寂九個月后推出了Midjourney V6&#xff0c;這個文生圖產品體現出的更細膩的細節處理&#xff0c;更強大的語言理解能力和更加“不像AI”的圖片效果在過去幾天引發一片驚呼。 作為一個閉源的模型產品&#xff0c;Midjourney的魔法配方并不為人所知&#xff0c;但…

HTTP 錯誤500.19 -Internal Server Error

HTTP 錯誤500.19 -Internal Server Error 原文:HTTP 錯誤500.19 -Internal Server Error HTTP 錯誤500.19 -Internal Server Error 錯誤代碼 0x80070021 asp.net 2009-11-05 16:54:33 閱讀484 評論1 字號&#xff1a;大中小 錯誤摘要 HTTP 錯誤500.19 -Internal Server Error …

連續內存分區式內存管理

目錄前言分區式內存管理動態分區內存管理總結本筆記參考黃工的https://mp.weixin.qq.com/s/k0W_LqI1zBAYC1GU1U2HQA 前言 內存管理模塊主要負責內存的初始化、分配以及釋放。 從分配內存是否連續可以分為兩大類&#xff1a; 1、連續內存管理 為進程分配的內存空間是連續的&a…