引用計數的原理和實例
引用計數是對共享的動態內存的一種管理方法,STL庫的string就是用到了引用計數的方法。本文簡單描述引用計數的原理,重點以一個實例來說明怎么在程序中實現引用計數。
1. 概念
引用計數用來記錄當前有多少指針指向同一塊動態分配的內存。當有指針指向這塊內存時,計數器加1;當指向此內存的指針銷毀時,計數器減1。當引用計數為0時,表示此塊內存沒有被任何指針指向,此塊被共享的動態內存才能被釋放。
2. STL庫的string利用引用計數共享內存
如下例:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s_1("aaaa");
printf("the address of s_1 is: %x\n", s_1.c_str());
string s_2("bbbb");
printf("the address of s_2 is: %x\n", s_2.c_str());
string s_3 = s_1;
printf("the address of s_3 is: %x\n", s_3.c_str());
string s_4 = s_3;
printf("the address of s_4 is: %x\n", s_4.c_str());
s_1 = s_2;
printf("the address of s_1 is: %x\n", s_1.c_str());
s_1[2] = 'a';
printf("the address of s_1 is: %x\n", s_1.c_str());
return 0;
}
結果如下:
the address of s_1 is: 9042014
the address of s_2 is: 904202c
the address of s_3 is: 9042014 //s_3與s_1共享同一塊內存
the address of s_4 is: 9042014 //s_4與s_1也共享同一塊內存
the address of s_1 is: 904202c //將s_2賦給s_1, s1與s_2也賦給同一塊內存, 此時s_3和s_4共享”aaaa”內存,s_1和s_2共享”bbbb”內存
the address of s_1 is: 9042044 //寫s_1, 新的內存分配給s1
STL string共享內存的原則(copy on write):
利用初始化或賦值生成多個內容相同的string,當沒有對這些string進行寫操作時,它們會共享同一塊內存。當有寫操作出現時,才會有新的內存重新分配。
3. 利用引用計數實現簡易String
問題:我們對String類的內存進行計數,但引用計數這個變量是類的什么類型的成員變量?
解答:
1) 普通私有成員變量,每個類都有一個獨立的計數器變量,在新的類對象拷貝構造和賦值的時候需要進入原來的類對象中去獲取這個計數器,再進行修改,在同一個類對象之間缺乏通用性。
2) static變量,類的所有對象公用一個計數器變量。字符串”aaaa”和”bbbb”使用不同的內存,它們應該分別有對應自己內存的計數器變量。
3) 結論,對每一塊內存分配一個變量,可以在動態分配字符串內存是多分配一個字節,將計數器的值放在第一個字節中;也可以在動態分配內存前先動態分配一個int型的內存來存放這個計數器。
String的代碼如下:
#include <iostream>
#include <cstring>
#include <cassert>
class String
{
public:
String(const char *str);
String(const String& other);
String& operator = (const String& other);
char& operator [] (int index);
~String();
private:
int *m_count;
char *m_data;
};
int main()
{
String s1("aaaa");
String s2("bbbb");
String s3 = s1;
String s4 = s3;
s1 = s2;
s1[2] = 'a';
return 0;
}
String::String(const char *str = NULL)
{
printf("---constructor---\n");
m_count = new int(0);
*m_count = 1;
if(str == NULL)
{
m_data = new char[1];
*m_data = '\0';
}
int length = strlen(str);
m_data = new char[length + 1];
strcpy(m_data, str);
printf("Allocate memory of %s at %x\n", m_data, m_data);
printf("The Refcount of %s is %d\n", m_data, *m_count);
}
String::String(const String& other)
{
printf("---copy constructor---\n");
m_count = other.m_count;
(*m_count)++;
m_data = other.m_data;
printf("The Refcount of %s is %d\n", m_data, *m_count);
}
String& String::operator = (const String& other)
{
printf("---assign value---\n");
if(this == &other)
{
return *this;
}
if(--(*m_count) == 0)
{
printf("Delete memeory of %s at %x\n", m_data, m_data);
delete[] m_data;
delete m_count;
//m_data = NULL;
//m_count = NULL;
}
m_count = other.m_count;
m_data = other.m_data;
(*m_count)++;
printf("The Refcount of %s is %d\n", m_data, *m_count);
return *this;
}
char& String::operator [] (int index)
{
printf("---operator []---\n");
int length = strlen(m_data);
assert(index >= 0 && index < length);
//引用計數為1時不用重新分配內存
if((*m_count) == 1)
{
return *(m_data+index);
}
//引用計數大于1時需要重新分配內存
if((*m_count) > 1)
{
(*m_count)--;
int tmp_count = *m_count;
m_count = new int(0);
*m_count = 1;
char* tmp = new char[length+1];
strcpy(tmp, m_data);
m_data = tmp;
printf("Re-Allocate memory at %x\n", m_data);
printf("The new Refcount (Re-Allocated) is %d\n", *m_count);
printf("The old Refcount is %d\n", tmp_count);
return *(m_data+index);
}
}
String::~String()
{
printf("---destructor---\n");
(*m_count) --;
printf("The Refcount of %s is %d\n", m_data, *m_count);
if((*m_count) == 0)
{
printf("Delete memeory of %s at %x\n", m_data, m_data);
delete[] m_data;
delete m_count;
//m_data = NULL;
//m_count = NULL;
}
}
運行結果如下:
---constructor---
Allocate memory of aaaa at 9509018
The Refcount of aaaa is 1
---constructor---
Allocate memory of bbbb at 9509038
The Refcount of bbbb is 1
---copy constructor---
The Refcount of aaaa is 2
---copy constructor---
The Refcount of aaaa is 3
---assign value---
The Refcount of bbbb is 2
---operator []---
Re-Allocate memory at 9509058
The new Refcount (Re-Allocated) is 1
The Refcount of original String bbbb is 1
---destructor--- //析構順序:s4, s3, s2, s1
The Refcount of aaaa is 1 //aaaa的引用計數為2,析構后減1
---destructor---
The Refcount of aaaa is 0 //aaaa的引用計數為0,釋放內存
Delete memeory of aaaa at 9509018
---destructor---
The Refcount of bbbb is 0
Delete memeory of bbbb at 9509038
---destructor---
The Refcount of bbab is 0
Delete memeory of bbab at 9509058
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成