靜態(tài)內(nèi)存谒所、棧內(nèi)存洗搂、動(dòng)態(tài)內(nèi)存
- 靜態(tài)內(nèi)存:保存局部
static
對(duì)象消返;類static
對(duì)象、已經(jīng)定義在任何函數(shù)之外的變量耘拇。 - 棧內(nèi)存:保存定義在函數(shù)內(nèi)的非
static
對(duì)象撵颊;
其中棧對(duì)象僅在其定義的程序塊運(yùn)行時(shí)才存在;static
對(duì)象在使用之前分配惫叛,程序結(jié)束時(shí)銷毀倡勇。
- 內(nèi)存池(稱為堆
heap
):存儲(chǔ)動(dòng)態(tài)分配的對(duì)象,即在程序運(yùn)行時(shí)分配的對(duì)象嘉涌,動(dòng)態(tài)內(nèi)存不在使用時(shí)妻熊,代碼必須顯式地銷毀它們。
提出智能指針:為了防止意外發(fā)生仑最,針對(duì)new
與delete
處理失誤的情況扔役;
- 智能指針(
smart pointer
):定于在memory
頭文件中,有shared_ptr
警医、unique_ptr
厅目;伴隨類weak_ptr
表示的弱引用。
shared_ptr
shared_ptr<string> p1; //可以指向string
shared_ptr<list<int>> p2;
//如果p1不為空,檢查它是否指向一個(gè)空string
if(p1 && p1->empty())
*p1 = "hi"; //如果p1指向一個(gè)空string损敷,解引用p1,將一個(gè)新值賦予string
-
make_shared
函數(shù)
使用時(shí)必須指定想要?jiǎng)?chuàng)建的對(duì)象的類型:
shared_ptr<int> p3 = make_shared<int>(42);
//p4指向一個(gè)值為"999999999"的string
shared_ptr<string> p4 = make_shared<string>(10,'9');
//p5指向值初始為0的int
shared_ptr<int> p5 = make_shared<string>();
通常使用auto
:
auto p6 = make_shared<vector<string>>();
拷貝和賦值
auto p = make_shared<int>(42); // p指向 的對(duì)象只有p一個(gè)引用
auto q(p); //p和q指向相同的對(duì)象深啤,此對(duì)象有兩個(gè)引用者
可以認(rèn)為被一個(gè)shared_ptr
都關(guān)聯(lián)一個(gè)引用計(jì)數(shù),一旦計(jì)數(shù)器的值變?yōu)?拗馒,它就會(huì)自動(dòng)釋放自己所管理的對(duì)象:
auto r = make_shared<int>(42); //r指向的int只有一個(gè)引用者
r = q; //給r賦值,令它指向另一個(gè)地址溯街;
// 遞增q指向的對(duì)象的引用計(jì)數(shù)诱桂;
// 遞減r原來指向的對(duì)象的引用計(jì)數(shù);
//r原來指向的對(duì)象已沒有引用者呈昔,會(huì)自動(dòng)釋放挥等;
下面的例子展示了使用動(dòng)態(tài)內(nèi)存的一個(gè)常見的原因是允許多個(gè)對(duì)象共享相同的狀態(tài):
Blob<string> b1; //空Blob
{
Blob<string> b2 = {"a"};
b1 = b2; //b1與b2共享相同的元素,b2被銷毀了堤尾,但b2中的元素不能銷毀肝劲;b1指向由最初b2創(chuàng)建的元素;
}
練習(xí)12-2:定義自己的const
函數(shù):
//
// Created by zc on 2019-08-21.
//
#include<iostream>
#include<vector>
#include<memory>
using namespace std;
class StrBlob
{
public:
typedef vector<string>::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
size_type size() const {return data->size();}
bool empty() const { return data->empty();}
// 添加郭宝、刪除元素
void push_back(const string &t){data->push_back(t);}
void pop_back();
// 訪問元素
string& front();
string& back();
string& front() const;
string& back() const;
private:
shared_ptr<vector<string>> data;
void check(size_type i, const std::string &msg) const;
};
StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}
StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)){}
//檢查是否越界
void StrBlob::check(size_type i, const string &msg) const
{
if (i >= data->size())
throw out_of_range(msg);
}
string& StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back()
{
check(0,"back on empty StrBlob");
return data->back();
}
//練習(xí)12-2
//目的:非常量函數(shù)不能夠調(diào)用常量對(duì)象
string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back() const
{
check(0, "front on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
//test
int main()
{
const StrBlob csb{"hello", "world", "zhengchu"};
StrBlob sb{"hello", "world", "jojo"};
std::cout<< csb.front() << " " << csb.back() << endl;
sb.back() = "dio";
cout<< sb.front() << " " << sb.back() << endl;
return 0;
}
hello zhengchu
hello dio
12-3:需要為上面的類添加const
版本的push_back
和pop_back
嗎
參考:https://www.douban.com/group/topic/61573279/
Ans:
可以用的原因辞槐,因?yàn)樾薷牡牟皇侵羔槪侵羔樦赶虻臄?shù)據(jù)粘室,因此完全可以用const
指針榄檬。
不可以用的原因:雖然在類的具體實(shí)現(xiàn)中,數(shù)據(jù)成員是一個(gè)指向vector的智能指針衔统;但由于類的封裝鹿榜,在類的使用者看來,數(shù)據(jù)成員是vector锦爵,他們并不知道具體的實(shí)現(xiàn)使用了智能指針舱殿。那么當(dāng)類的使用者聲明類的常量對(duì)象時(shí),他們期待的結(jié)果是vector的內(nèi)容不會(huì)被改變棉浸。所以我們?cè)谠O(shè)計(jì)這個(gè)類的時(shí)候怀薛,要考慮到類的使用者的真實(shí)意圖,對(duì)于像push_back和pop_back這樣會(huì)改變智能指針?biāo)赶虻膙ector內(nèi)容的成員函數(shù)迷郑,我們不應(yīng)該聲明和定義成const版本枝恋。這樣在類的使用者使用類的常對(duì)象時(shí),就不能調(diào)用push_back和pop_back成員函數(shù)嗡害,不能改變智能指針?biāo)赶虻膙ector的內(nèi)容了焚碌,這正好與類的使用者的意圖相符。