亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

詳解C++句柄類

2020-05-23 13:26:50
字體:
來源:轉載
供稿:網友

上一篇文件介紹了關于C++代理類的使用場景和實現方法,但是代理類存在一定的缺陷,就是每個代理類會創建一個新的對象,無法避免一些不必要的內存拷貝,本篇文章引入句柄類,在保持代理類多態性的同時,還可以避免進行不不要的對象復制。

我們先來看一個簡易的字符串封裝類:MyString,為了方便查看代碼,將函數的聲明和實現放到了一起。

class MyString{public: // 默認構造函數 MyString() {  std::cout << "MyString()" << std::endl;  buf_ = new char[1];  buf_[0] = '/0';  len_ = 0; } // const char*參數的構造函數 MyString(const char* str) {  std::cout << "MyString(const char* str)" << std::endl;  if (str == nullptr)  {   len_ = 0;   buf_ = new char[1];   buf_[0] = '/0';  }  else  {   len_ = strlen(str);   buf_ = new char[len_ + 1];   strcpy_s(buf_, len_ + 1, str);  } } // 拷貝構造函數 MyString(const MyString& other) {  std::cout << "MyString(const MyString& other)" << std::endl;  len_ = strlen(other.buf_);  buf_ = new char[len_ + 1];  strcpy_s(buf_, len_ + 1, other.buf_); } // str1 = str2; const MyString& operator=(const MyString& other) {  std::cout << "MyString::operator=(const MyString& other)" << std::endl;  // 判斷是否為自我賦值  if (this != &other)  {   if (other.len_ > this->len_)   {    delete[]buf_;    buf_ = new char[other.len_ + 1];   }   len_ = other.len_;   strcpy_s(buf_, len_ + 1, other.buf_);  }  return *this; } // str = "hello!"; const MyString& operator=(const char* str) {  assert(str != nullptr);  std::cout << "operator=(const char* str)" << std::endl;  size_t strLen = strlen(str);  if (strLen > len_)  {   delete[]buf_;   buf_ = new char[strLen + 1];  }  len_ = strLen;  strcpy_s(buf_, len_ + 1, str);    return *this; }  // str += "hello" void operator+=(const char* str) {  assert(str != nullptr);  std::cout << "operator+=(const char* str)" << std::endl;  if (strlen(str) == 0)  {   return;  }  size_t newBufLen = strlen(str) + len_ + 1;  char* newBuf = new char[newBufLen];  strcpy_s(newBuf, newBufLen, buf_);  strcat_s(newBuf, newBufLen, str);  delete[]buf_;  buf_ = newBuf;  len_ = strlen(buf_); } // 重載 ostream的 <<操作符 ,支持 std::cout << MyString 的輸出 friend std::ostream& operator<<(std::ostream &out, MyString& obj) {  out << obj.c_str();  return out; } // 返回 C 風格字符串 const char* c_str() {  return buf_; } // 返回字符串長度 size_t length() {  return len_; } ~MyString() {  delete[]buf_;  buf_ = nullptr; }private: char* buf_; size_t len_;};

看一段測試程序

#include "MyString.h"int _tmain(int argc, _TCHAR* argv[]){ MyString str1("hello~~"); MyString str2 = str1; MyString str3 = str1; std::cout << "str1=" << str1 << ", str2=" << str2 << ", str3=" << str3; return 0;}

輸出內容如下:

C++,句柄類

可以看到,定義了三個MyString對象,str2和str3都是由str1拷貝構造而來,而且在程序的運行過程中,str2和str3的內容并未被修改,但是str1和str2已經復制了str1緩沖區的內容到自己的緩沖區中。其實這里可以做一個優化,就是讓str1和str2在拷貝構造的時候,直接指向str1的內存,這樣就避免了重復的內存拷貝。但是這樣又會引出一些新的問題:

1. 多個指針指向同一塊動態內存,內存改何時釋放?由誰釋放?

2. 如果某個對象需要修改字符串中的內容,該如和處理?

解決這些問題,在C++中有兩個比較經典的方案,那就是引用計數和Copy On Write。

在引用計數中,每一個對象負責維護對象所有引用的計數值。當一個新的引用指向對象時,引用計數器就遞增,當去掉一個引用時,引用計數就遞減。當引用計數到零時,該對象就將釋放占有的資源。

下面給出引用計數的一個封裝類:

class RefCount{public: RefCount() : count_(new int(1)){}; RefCount(const RefCount& other) : count_(other.count_) {  ++*count_; } ~RefCount() {  if (--*count_ == 0)  {   delete count_;   count_ = nullptr;  } } bool Only() {  return *count_ == 1; } void ReAttach(const RefCount& other) {  // 更新原引用計數的信息  if (Only())  {   delete count_;  }  else  {   --*count_;  }  // 更新新的引用計數的信息  ++*other.count_;    // 綁定到新的引用計數  count_ = other.count_; } void MakeNewRef() {  if (*count_ > 1)  {   --*count_;   count_ = new int(1);  } }private: int* count_;};

Copy On Write:就是寫時復制,通過拷貝構造初始化對象時,并不直接將參數的資源往新的對象中復制一份,而是在需要修改這些資源時,將原有資源拷貝過來,再進行修改,就避免了不必要的內存拷貝。

下面的代碼是完整的句柄類MyStringHandle。每一個句柄類,都包含一個引用計數的類,用來管理和記錄對MyString對象的引用次數。

class MyStringHandle{public: MyStringHandle() : pstr_(new MyString){} // 這兩種參數的構造函數必須構造一個新的MyString對象出來 MyStringHandle(const char* str) : pstr_(new MyString(str)) {} MyStringHandle(const MyString& other) : pstr_(new MyString(other)) {} // 拷貝構造函數,將指針綁定到參數綁定的對象上,引用計數直接拷貝構造,在拷貝構造函數內更新引用計數的相關信息 MyStringHandle(const MyStringHandle& ohter) : ref_count_(ohter.ref_count_), pstr_(ohter.pstr_) {} ~MyStringHandle() {  if (ref_count_.Only())  {   delete pstr_;   pstr_ = nullptr;  } } MyStringHandle& operator=(const MyStringHandle& other) {  // 綁定在同一個對象上的句柄相互賦值,不作處理  if (other.pstr_ == pstr_)  {   return *this;  }  // 若當前引用唯一,則銷毀當前引用的MyString  if (ref_count_.Only())  {   delete pstr_;  }  // 分別將引用計數和對象指針重定向  ref_count_.ReAttach(other.ref_count_);  pstr_ = other.pstr_;  return *this; } // str = "abc" 這里涉及到對字符串內容的修改, MyStringHandle& operator=(const char* str) {  if (ref_count_.Only())  {   // 如果當前句柄對MyString對象為唯一的引用,則直接操作改對象進行賦值操作   *pstr_ = str;  }  else  {   // 如果不是唯一引用,則將原引用數量-1,創建一個新的引用,并且構造一個新的MyString對象   ref_count_.MakeNewRef();   pstr_ = new MyString(str);  }  return *this; }private: MyString* pstr_; RefCount ref_count_;};

看一段測試程序:

int _tmain(int argc, _TCHAR* argv[]){ // 構造MyString MyStringHandle str1("hello~~"); // 不會構造新的MyString MyStringHandle str2 = str1; MyStringHandle str3 = str1; MyStringHandle str4 = str1; // 構造一個空的MyString MyStringHandle str5; // 將str1賦值到str5,不會有內存拷貝 str5 = str1; // 修改str5的值 str5 = "123"; str5 = "456"; return 0;}

C++,句柄類

總結

本篇文章介紹了C++句柄類的設計思想與簡單實現,主要通過引用計數和Copy On Write實現,這兩種思想還是很經典的,垃圾回收、智能指針的實現都有借鑒這兩種思想。水平有限,可能會有一些錯誤或者描述不明確,歡迎大家拍磚~~


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美黑人极品猛少妇色xxxxx| 欧美大成色www永久网站婷| 欧美成人午夜剧场免费观看| 亚洲欧美日本伦理| 91成人精品网站| 原创国产精品91| 欧美一级黑人aaaaaaa做受| 亚洲美女在线观看| 国产69精品久久久久9999| 国产精品久久久久久久久免费看| 久久久久国产精品免费网站| 欧美刺激性大交免费视频| 91精品国产乱码久久久久久蜜臀| 国产91在线播放精品91| 色噜噜国产精品视频一区二区| 在线观看中文字幕亚洲| 国产99久久精品一区二区 夜夜躁日日躁| 中文字幕亚洲图片| 亚洲加勒比久久88色综合| 久久亚洲综合国产精品99麻豆精品福利| 久久久视频免费观看| 亚洲色图美腿丝袜| 欧美性xxxx极品高清hd直播| 欧美成人在线免费| 91久久精品视频| 亚洲最大中文字幕| 一本色道久久综合狠狠躁篇怎么玩| 1769国内精品视频在线播放| 欧美国产在线电影| 欧美精品一区二区三区国产精品| 久久精品一本久久99精品| 欧美黄网免费在线观看| 日韩精品中文字| 日韩成人在线视频网站| 激情成人在线视频| 国产精品高精视频免费| 欧美一级视频免费在线观看| 中文字幕精品一区二区精品| 久久人人爽人人爽人人片av高请| 成人在线一区二区| 日韩在线播放av| 国外成人性视频| 亚洲精品日韩欧美| 亚洲日本成人网| 26uuu另类亚洲欧美日本一| 亚洲成人性视频| 亚洲精品一区二区在线| 日韩视频免费在线观看| 中文字幕国内精品| 日韩中文字幕在线视频播放| 国产精品视频精品视频| 国产香蕉精品视频一区二区三区| 日韩av高清不卡| 精品中文字幕在线2019| 日韩av免费在线播放| 精品久久久精品| 日韩在线免费视频观看| 日韩视频免费在线| 在线视频一区二区| 欧美亚洲一级片| 九九久久久久99精品| 97在线视频一区| 国产精品igao视频| 日本一区二区在线播放| 欧美成人精品一区二区| 国产精品99久久久久久人| 日韩电影免费观看在线| 成人a在线观看| 欧美国产视频日韩| 久久久亚洲精品视频| 2019亚洲男人天堂| 欧美黑人国产人伦爽爽爽| 国产精品视频大全| 国产精品视频公开费视频| 亚洲欧美中文日韩在线v日本| 亚洲欧美制服中文字幕| 中文欧美在线视频| 最新国产成人av网站网址麻豆| 亚洲精品一区二区网址| 亚洲一区二区三区视频| 色99之美女主播在线视频| 久久精品成人欧美大片| 最新亚洲国产精品| 精品欧美国产一区二区三区| 色妞色视频一区二区三区四区| 国产精品亚洲欧美导航| 国产精品91免费在线| 亚洲精品一区中文| 国产精品久久久久久久久久小说| 97avcom| 成人av电影天堂| 正在播放国产一区| 国产在线观看不卡| 欧美精品激情视频| 久久久久久久香蕉网| 91精品国产色综合久久不卡98| 日韩欧亚中文在线| 欧美在线影院在线视频| 国产精品露脸av在线| 欧美电影《睫毛膏》| 亚洲自拍偷拍区| 亚洲精品免费一区二区三区| 欧美大秀在线观看| 欧美色视频日本版| 久久久久久高潮国产精品视| 欧美一区二粉嫩精品国产一线天| 国产乱人伦真实精品视频| 97视频在线观看免费| 国产精品人成电影在线观看| 成人欧美一区二区三区在线湿哒哒| www.日韩欧美| 亚洲91av视频| 精品久久香蕉国产线看观看gif| 亚洲免费电影一区| 亚洲a级在线播放观看| 这里只有视频精品| 国产成人亚洲精品| 欧美激情精品久久久久久久变态| 国产精品久久久久久久久久久久久久| 日韩精品中文字幕在线播放| 国产一区二区三区高清在线观看| 北条麻妃99精品青青久久| 亚洲精品资源美女情侣酒店| 国产在线98福利播放视频| 中文在线不卡视频| 亚洲高清福利视频| 在线精品国产成人综合| 亚洲精品欧美极品| 国产一区二区三区免费视频| 日韩精品一二三四区| 久久天天躁狠狠躁夜夜av| 久久中文久久字幕| 一区二区三区 在线观看视| 国产精品久久久久久av下载红粉| 91免费在线视频| 日韩中文字幕精品视频| 97精品视频在线| 在线精品国产欧美| 欧美成人精品h版在线观看| 国产精品成人品| 精品色蜜蜜精品视频在线观看| 欧美黄色www| 欧美黑人巨大xxx极品| 亚洲少妇激情视频| 日产精品99久久久久久| 欧美日韩亚洲视频一区| 精品一区二区三区电影| 欧美成人三级视频网站| 国内自拍欧美激情| 91啪国产在线| 国产午夜精品久久久| 亚洲午夜性刺激影院| 欧美中文字幕在线视频| 91久久久国产精品| 亚洲护士老师的毛茸茸最新章节| 欧美视频免费在线观看| 精品露脸国产偷人在视频| 成人激情av在线| 日韩欧美国产骚| 国内精品一区二区三区四区| 亚洲国产欧美在线成人app| 欧美日本高清一区| 91福利视频在线观看| 久久香蕉国产线看观看av|