## 模æ¿
#### 彿°æ¨¡æ¿
模æ¿å®ä¹ä»¥å
³é®åtemplateå¼å§ï¼<>ä¸å
å«ä¸ä¸ªæ¨¡æ¿åæ°å表ï¼é颿¯ä¸ä¸ªéå·åéçä¸ä¸ªæå¤ä¸ªæ¨¡æ¿åæ°ã
模æ¿çå®ä¹ç±»ä¼¼å½æ°çå®ä¹ï¼ç¼è¯å¨æ ¹æ®å®é
è°ç¨çåæ°ç±»åç¼ååºå¯¹åºç±»åç彿°ï¼å¹¶ç¼è¯è¿ä¸ªå½æ°ã
模æ¿éè¦å¨ç¼è¯æç´å°æ°æ®çç±»åï¼è夿åä¸ç¨
```c++
template
int compare(const T& left, const T& right)
{
if (left < right) return -1;
if (left > right) return 1;
return 0;
}
```
T æ¶æ¨¡æ¿ç±»ååæ°ï¼å¯ä»¥çä½ç±»å说æç¬¦ï¼å¯ä»¥ç¨typenameæclassæ¥å£°æï¼å¨æ¨¡æ¿åæ°å表ä¸å¯ä»¥åæ¶ä½¿ç¨è¿ä¸¤ä¸ªå
³é®åï¼ææä¸æ¨¡ä¸æ ·ã使¯ä½¿ç¨typenameå
³é®åæ´ç´è§ï¼ä¸ä¼è¢«è¯¯è§£ã模æ¿ç±»ååæ°åå¿
é¡»ætypenameç修饰
```c++
template
T calc(const T& a, const U& b)
{
T tmp = a + b;
return tmp;
}
```
模æ¿è¿å¯ä»¥ä½¿ç¨éç±»ååæ°ï¼å®æ è¯ä¸ä¸ªå¼ï¼èéä¸ä¸ªç±»åãéç±»ååæ°çæ¨¡æ¿å®åå¿
é¡»æ¶å¸¸é表达å¼ï¼å 为模æ¿å¨ç¼è¯æè¢«å®ä¾å为ä¸ä¸ªå
·ä½ç彿°ï¼æ¤æ¶éè¦ç¥éå
·ä½ç弿è½å®ä¾åã
```c++
template
int compare(const char (&p1)[N], const char (&p2)[M])
{
return strcmp(p1, p2);
}
```
å½è°ç¨`compare("good", "god");`æ¶ï¼ç¼è¯å¨ä¼ä½¿ç¨åé¢å¸¸éç大å°ä»£æ¿NåMï¼æ¤å¤ä¸ºï¼
`int compare(const char (&p1)[5], const char (&p2)[4])`
ä¸ä¸ªéç±»ååæ°å¯ä»¥æ¯ä¸ä¸ªæ´åï¼æè
ä¸ä¸ªæå对象æå½æ°ç±»åçæéæ(å·¦å¼)å¼ç¨ãç»å®å°æéæå¼ç¨éç±»ååæ°çå®åå¿
é¡»å
·æéæççåæãä¸è½ä½¿ç¨ä¸ä¸ªæ®éç(éstatic)å±é¨åéæå¨æå¯¹è±¡ä½ä¸ºæéæå¼ç¨éç±»åæ¨¡æ¿åæ°çå®åãæéå¯ä»¥ä½¿ç¨nullptræå¼ä¸º0ç常éè¡¨è¾¾å¼æ¥å®ä¾åã
#### ç¼åç±»åæ å
³ä»£ç
* å°æ¨¡æ¿å½æ°çåæ°è®¾å®ä¸ºconstå¼ç¨ï¼ä¿è¯å½æ°å¯ä»¥ç¨äºä¸è½æ·è´ç±»åã
* 彿°ä½å
å¯¹æ°æ®ç±»åçæä½è¦æ±æå°ï¼ä¾å¦ä¸æ¯ææçç±»åé½å®ç°äºææè¿ç®ç¬¦ï¼æä»¥å¯¹å®åç±»åè¦æ±è¶å°ï¼å°±è¶éç¨
#### 模æ¿ç¼è¯
ç¼è¯å¨åªä¼å¨æä»¬å®ä¾å模æ¿çä¸ä¸ªç¹å®çæ¬æ¶ï¼æä¼çæä»£ç ã
å½è°ç¨ä¸ä¸ªæ®é彿°æ¶ï¼ç¼è¯å¨åªéè¦ææ¡å½æ°ç声æï¼ä½¿ç¨ä¸ä¸ªç±»ç±»å对象æ¶ï¼ç±»çå®ä¹å¿
é¡»æ¯å¯ç¨çï¼ä½å
¶ä¸çæå彿°çå®ä¹ä¸å¿
å·²ç»åºç°ï¼å æ¤ä¸è¬æç±»çå®ä¹å彿°å£°ææ¾å¨å¤´æä»¶ä¸ï¼ç±»æå彿°åæ®é彿°çå®ä¹æ¾å¨æºæä»¶ä¸ã
模æ¿ç头æä»¶é常å
æ¬å£°æåå®ä¹ï¼ç¼è¯å¨éè¦ææ¡å½æ°æ¨¡æ¿æç±»æ¨¡æ¿æå彿°çå®ä¹æè½å®ä¾åä¸ä¸ªæ¨¡æ¿ççæ¬ã
å½ä½¿ç¨æ¨¡æ¿æ¶ï¼ææä¸ä¾èµäºæ¨¡æ¿åæ°çååé½å¿
é¡»æ¯å¯è§çï¼å½æ¨¡æ¿è¢«å®ä¾åæ¶ï¼æ¨¡æ¿çå®ä¹ï¼å
æ¬ç±»æ¨¡æ¿æåçå®ä¹ï¼é½å¿
é¡»æ¶å¯è§çï¼è¿æ¯ææ¨¡æ¿çæä¾è
ä¿éçã
ç¨æ¥å®ä¾å模æ¿çææåæ°ãç±»å以åä¸ç±»åå
³èçè¿ç®ç¬¦ç声æé½å¿
é¡»æ¯å¯è§ï¼è¿æ¯ç±æ¨¡æ¿ç使ç¨è
æ¥ä¿è¯çã
#### 类模ç
ç¼è¯å¨ä¸è½ä¸ºç±»æ¨¡æ¿æ¨ææ¨¡æ¿åæ°çç±»åï¼å æ¤å¨ä½¿ç¨ç±»æ¨¡æ¿æ¶ï¼éè¦æç¡®æåºç±»åä¿¡æ¯ï¼ä¾å¦`vector`
å¨ç±»æ¨¡æ¿åå
¶æåçå®ä¹ä¸ï¼æä»¬å°æ¨¡æ¿åæ°å½ä½æ¿èº«ï¼ä»£æ¿ä½¿ç¨æ¨¡æ¿æ¶ç¨æ·æä¾çç±»åæå¼ã
类模ççåå䏿¯ä¸ä¸ªç±»ååï¼å®æ¯ç¨æ¥å®ä¾åä¸ä¸ªç±»åçã妿ä¸ä¸ªç±»æ¨¡æ¿ä¸ä½¿ç¨äºå¦ä¸ä¸ªæ¨¡æ¿ï¼é常ä¸å°ä¸ä¸ªå®é
ç±»åæå¼çååç¨ä½å
¶æ¨¡æ¿å®åï¼èæ¯å°æ¨¡æ¿èªå·±çåæ°å½ä½è¢«ä½¿ç¨æ¨¡æ¿çå®åã
```c++
template
class Blob
{
public:
typedef T value_type;
typedef typename std::vector::size_type size_type;
Blob();
Blob(std::initializer_list il);
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const T &t) { data->push_back(t);}
void push_back(T &&t) { data->push_back(std::move(t)); }
void pop_back();
T& back();
T& operator[](size_type i);
private:
// å°æ¨¡æ¿æµåæ°ä½ä¸ºå
é¨ä½¿ç¨ç模æ¿çå®å
std::shared_ptr<:vector>> data;
void check(size_type i, const std::string &msg) const;
};
```
##### ç±»æ¨¡æ¿æå彿°
å®ä¹å¨ç±»æ¨¡æ¿å
çæå彿°è¢«éå¼å£°æä¸ºå
è彿°ãé»è®¤æ
åµä¸ï¼å¯¹äºä¸ä¸ªå®ä¾åç类模æ¿ï¼å
¶æååªæå¨ä½¿ç¨æ¶æè¢«å®ä¾åã
å®ä¹å¨ç±»å¤é¨çæå彿°ï¼ä¸æ ·éè¦ç¬¦å`ret-type class_type::member-name(param-list)`èå¼ã
```c++
template
Blob::Blob():data(std::make_shared<:vector>>())
{
//æé 彿°ä¸åé
ä¸ä¸ªç©ºvectorï¼å¹¶å°vectorçæéä¿åå¨dataä¸
}
// use: Blob words = { "a", "an", "the"};
template
Blob::Blob(std::initializer_list il):data(std::make_shared<:vector>>(il))
{
}
template
void Blob::pop_back()
{
check(0, "pop_back on empty Blob");
data->pop_back();
}
template
T& Blob::back()
{
check(0, "back on empty Blob");
return data->back();
}
template
T& Blob::operator[](size_type i)
{
check(i, "subscript out of the range");
return (*data)[i];
}
template
void Blob::check(size_type i, const std::string &msg) const
{
if (i >= data->size())
throw std::out_of_range(msg);
}
```
##### 使ç¨ç±»æ¨¡æ¿
```C++
Blob squares = {0, 1, 2, 3, 4, 5};
for (size_t i = 0; i != squares.size(); i++)
{
squares[i] = i*i;
}
```
å¨ç±»ä»£ç å
ç®å模æ¿ç±»åç使ç¨
å¨ç±»æ¨¡æ¿èªå·±çä½ç¨åä¸ï¼æä»¬å¯ä»¥ç´æ¥ä½¿ç¨æ¨¡æ¿è䏿ä¾å®åã
```c++
template
class BlobPtr
{
public:
BlobPtr(): curr(0) {}
BlobPtr(Blob &a, size_t sz = 0):wptr(a.data), curr(sz) {}
T& operator*() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
// åç½®è¿ç®ç¬¦
// ç¼è¯å¨èªå¨ä¼å¤çå®åç±»åï¼ä¸éè¦æ¾å¼è¯´æBlobPtr&
BlobPtr& operator++()
{
check(curr, "dereference past end");
++curr;
return *this;
}
BlobPtr& operator--();
BlobPtr operator++(int);
private:
//è¿åä¸ä¸ªæåvectorçshared_ptr
std::shared_ptr<:vector>> check(std::size_t, const std::string&) const;
// ä¿åä¸ä¸ªweak_ptr,æ è¯åºå±vectorå¯è½è¢«éæ¯
std::weak_ptr<:vector>> wptr;
std::size_t curr; // æ°ç»æ»å½åçä½ç½®
};
// åç½®ï¼éå¢å¯¹è±¡ä½è¿ååå¼ï¼æ¤å¤è¿åå¼ä¸æ¯å¼ç¨
// å¨ç±»çä½ç¨åå¤ï¼å°±éè¦å®æ´ç忰声æ
template
BlobPtr BlobPtr::operator++(int)
{
//æ¤æ¶ååç±»çä½ç¨åå
BlobPtr ret = *this; // save curr value
++*this; // æ¨è¿ä¸ä¸ªå
ç´ ;åç½®++æ£æ¥é墿¯å¦åæ³
return ret;
}
```
### Chapter 12.1
##### 12.1.1 æºè½æé
ç¨åºä¸ä½¿ç¨å¨æå
åçå°æ¹ï¼
1. ä¸ç¥ééè¦å¤å°å¯¹è±¡ï¼æ°å䏿¯å¸¸éï¼èæ¯è¿è¡æ¶æç¥éç
2. ä¸ç¥éå
·ä½éè¦åªç§ç±»åç对象ï¼å¤æ
3. å¨å¤ä¸ªå¯¹è±¡ä¹é´å
±äº«æ°æ®
C++åºçæºè½æéæä¸ç±»ï¼`shared_ptr` `unique_ptr` `weak_ptr`ï¼ä»¥ä¸é½å¨``ä¸å®ä¹
æºè½æé乿¯éè¿æ¨¡æ¿æ¥å®ç°çï¼å æ¤ä¹éè¦åè¯ä»æ°æ®ç±»å
`shared_ptr p1`å®ä¹äºä¸ä¸ªæåstringç±»åç`shared_ptr`ï¼é»è®¤ä¸ºnull.
`shared_ptr> p2`å®ä¹äºä¸ä¸ªæåä¸ä¸ªintç±»åçlistç`shared_ptr`.
æºè½æéçç¨æ³åæ®éç±»åçæéç¨æ³ä¸æ ·ã彿åä¸ä¸ªæå卿å
åç`shared_ptr`è¢«éæ¾çæ¶åï¼å®ä¼éæ¾å¨æå
åçèµæºï¼è°ç¨å
¶ææå½æ°ã
```c++
// 夿æé妿ä¸ä¸ºnullï¼å夿æ¯å¦æ¯ä¸ä¸ªç©ºå符串
if (p1 && p1->empty())
*p1 = "hi"; // 妿æ¯ç©ºå符串ï¼ç»å®èµå¼
```
`shared_ptr`å`unique_ptr`齿¯æçæä½
* `shared_ptr sp` null smart pointer that can point to objects of type T
* `sp` use sp as a condition; true if sp points to an object
* `*sp` Dereference sp to get the object to which p points
* `p->mem` Synonym for `(*p).mem`
* `p.get()` Return the pointer in p. ä¸è¦ç´æ¥ä½¿ç¨è¿ä¸ªæéï¼å®éæ¶å¯è½è¢«æºè½æééæ¾
* `swap(p, q)` `p.swap(q)` Swaps the pointers in p and q
`shared_ptr`ç¹æçæä½
* `make_shared(args)` Returns a `shared_ptr` pointing to a dynamically allocated object of type T. Uses args to initialize the object
* `shared_ptr p(q)` p is a copy of `shared_ptr` q; å¢å qéé¢ç计æ°ï¼qéé¢çæéå¿
é¡»å¯ä»¥è½¬æ¢ä¸º`T*`ç±»å
* `p=q` åå°péé¢ç计æ°ï¼å¦æpéé¢ç计æ°ä¸º0éæ¾pæåçå
åï¼å¢å qä¸ç计æ°ï¼å·¦è¾¹å¯¹è±¡åæ¥çåå°è®¡æ°ï¼å³è¾¹çå¢å 计æ°ã
* `p.use_count()` è¿åæå¤å°ä¸ªå¯¹è±¡åpå
±ç¨ï¼è¿æ¯ä¸ªèæ¶æä½ï¼ç¨äºè°è¯
* `p.unique()` returns true if `p.use_count()` is one; false otherwise
æå¥½ä½¿ç¨`make_shared(args)`æ¹å¼å®ä¹ä¸ä¸ªæºè½æé
```c++
// shared_ptr that points to an int with value 42
shared_ptr spInt = make_shared(42);
// points to a string with value 9999999999
shared_ptr spStr = make_shared(10, '9');
// points to an int that is value initialized to 0
auto spInt0 = make_shared(); // 使ç¨autoèªå¨è¯å«ç±»å
```
`shared_ptr`ä¹é´çèµå¼ãæ·è´æé 齿¯å¢å å¼ç¨è®¡æ°ï¼ä¸ä¼éæ°åé
å
åãå æ¤å¯ä»¥æå½æ°å
卿ç³è¯·çå
åéè¿`shared_ptr`ä½ä¸ºè¿åå¼è¿åã
```c++
// å·¥å彿°è¿åä¸ä¸ªæé
shared_ptr factory()
{
return make_shared();
}
// å
¶ä»ä½¿ç¨çå°æ¹ï¼å½æ§è¡å°æ¬å·å¤éåºä½ç¨åæ¶ï¼éæ¾èµæº
{
shared_ptr sp = factory();
sp->play();
}
```
ç±äºåªè¦æå¼ç¨åå¨ï¼`shared_ptr`æåçèµæºå°±ä¸ä¼è¢«éæ¾ï¼å æ¤å¨ä½¿ç¨æ¶éè¦æ³¨ææä¸å¨ç¨ç`shared_ptr`峿¶éæ¾ï¼é¿å
å ç¨å
åèµæºãä¾å¦å¨vectorä¸åæ¾çæ¯`shared_ptr`ç对象ï¼å¦ævector䏿ä¸é¨åç对象已ç»ä¸éè¦ä½¿ç¨äºï¼å¦æä¸å é¤ï¼è¿äºå¯¹è±¡ä¼ä¸ç´å ç¨çå
åã
If you put `shared_ptr` in a container, and you subsequently need to use some, but not all, of the elements, remember to erase the elements to you no longer need.
对äºvectorèè¨ï¼å½vectorèªèº«éæ¯æ¶ï¼åæ¾å¨å®éé¢çå
ç´ ä¹ä¼è¢«éæ¯ï¼æ·è´æ¶ï¼ä¹ä¼ç´æ¥æ·è´å®éé¢çå
ç´ ãä¾å¦ä¸é¢çä¾åå°±æ æ³å®ç°å¨å¤ä¸ªå¯¹è±¡ä¹é´å
±äº«æ°æ®çç®çãæ°æ®æ¯æ·è´äºå¤æ¬¡ã
```c++
vector v1; // empty vector
{
vector v2 = { "a", "an", "the" };
v1 = v2;
}// v2 is destroyed, which destroys the elements in v2
// v1 has three elements, which are copies of the ones originally in v2
```
ä¸ä¸ªå¯¹è±¡çæåå¨è¿ä¸ªå¯¹è±¡éæ¯æ¶ä¹ä¼è¢«éæ¯ï¼å æ¤éè¦æè¿ä¸ªæåå®ä¹ä¸ºå¨æå
åï¼æä¸ä¼è¢«éæ¾ãéè¿ä½¿ç¨`shared_ptr`ä½ä¸ºæåï¼å½ä¸ä¸ªå¯¹è±¡çæåéæ¾åï¼è¿æå
¶ä»å¯¹è±¡çæåæè¿ä¸ªå¨æå
åçå¼ç¨ï¼å æ¤ä¸ä¼è¢«éæ¾æã
模æ¿ç« èç`class Blob`å°±éè¿å®ä¹`std::shared_ptr<:vector>> data`ä½ä¸ºæååéï¼è¾¾å°å¨å¤ä¸ªå¯¹è±¡ä¹é´å
±äº«dataçç®çã彿·è´ãèµå¼`Blob`ç对象æ¶ï¼å
¶å
鍿ådataä¹ä¼è¢«ç´æ¥æ·è´ãèµå¼ï¼ä»èå¢å äºdataçå¼ç¨è®¡æ°ã
ä¸é¢ä¾åä¸ï¼æç»b1䏿4个对象ï¼åvectorççæ¬ä¸åã
```C++
Blob b1;
{
Blob b2 = { "a", "an", "the" };
b1 = b2;
b2.push_back("about");
}
```
##### 12.1.2 ç´æ¥ç®¡ç卿å
å
妿ä¸ä¸ªç±»ç´æ¥ç®¡çå
åï¼é£ä¹å®çæ·è´ãèµå¼ã忿彿°éè¦é¢å¤æ³¨æå
åçæ·è´ã
éè¿newåé
ç对象ä¼è°ç¨é»è®¤çæé 彿°ï¼ä½æ¯å¯¹äºå
建类åå¦intãå¤åç±»åå¦ç»æä½ï¼å没æåå§åï¼æ¯æªå®ä¹çå¼ã
å½ç¶ä¹å¯ä»¥newçæ¶åä¹é´è°ç¨æå®çæé 彿°
```c++
int *pi = new int(1024); // object to which pi points has value 1024
string *ps = new string(10, '9'); // *ps is "9999999999"
// C++11 vector with ten elements with values from 0 to 9
vector *pv = new vector{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
```
æ°çC++æ åä¸auto使ç¨åå§ååéçç±»åç±»æ¨å¯¼å®ä¹çåéçç±»å
```c++
auto p1 = new auto(obj); // p points to an object of the type of obj
// that object is initialized from obj. If obj is an int, then p1 is int*; if obj is a string, then p1 is a string*
auto p2 = new auto{a,b,c}; // error: must use parentheses for the initializer
```
* å¯ä»¥ä½¿ç¨newæ¥å建常éå¯¹è±¡ï¼æ¤æ¶å¿
é¡»æåå§åï¼å¾å°çæéæ¯æå常éçã
```c++
// allocate and initialize a const int
const int *pci = new const int(1024);
// allocate a default-initialized const empty string
const string *pcs = new const string;
```
* å½å
åæ æ³æ»¡è¶³newç大尿¶ï¼new伿åº`bad_alloc`å¼å¸¸ãæä»¬å¯ä»¥é»æ¢æåºå¼å¸¸ä½¿ç¨placement new.è¿æ¶å¯ä»¥ä¼ éä¸ä¸ªåæ°ç»newï¼è¿éä¼ éåºæä¾çnothrowåè¯newä¸è¦æåºå¼å¸¸ï¼èæ¯è¿ånullãéè¦è¿ä¸ªå¤´æä»¶ã
```c++
// if allocation fails, new returns a null pointer
int *p2 = new (nothrow) int;
```
* deleteåªè½å¯¹nullæå¨æåé
çå
åææ
* ç¼è¯å¨æ æ³åºåä¸ä¸ªå°åæ¯å¨æåé
çè¿æ¯éæææ¬å°åé
* ä¸ä¸ªå¸¸éå¯¹è±¡æ æ³æ´æ¹ï¼ä½æ¯å¨æåé
ç常éå¯ä»¥éæ¯ã
```c++
int i, *pi1 = &i, *pi2 = nullptr;
double *pd = new double(33), *pd2 = pd;
delete i; // error: i is not a pointer
delete pi1; // undefined: pi1 refers to a local
delete pd; // ok
delete pd2; // undefined: the memory pointed to by pd2 was already freed
delete pi2; // ok: it is always ok to delete a null pointer
const int *pci = new const int(1024);
delete pci; // ok: deletes a const object
```
使ç¨newåé
çå
å妿ä¸éæ¾ï¼ä¼é æå
åæ³æ¼
deleteä¸ä¸ªæéåä¸å®è¦ææå该å°åçæææéé½èµå¼ä¸ºnullptrï¼å¦åé£ä¸ªæéå°±æ¯éæéï¼å®¹æåºç°é误ã
##### 12.1.3 使ç¨`new`å`shared_ptr`
* `shared_ptr p(q)` p管çnewåºæ¥ççæéqï¼qå¿
é¡»å¯ä»¥è½¬æ¢ä¸º`T*`
* `shared_ptr p(u)` p仿䏿é(unique_ptr)ué£éè·åäºæéæææï¼uç°å¨æ¯null
* `shared_ptr p(q, d)` p声æäºå
建æéqï¼på°ä¼ä½¿ç¨callable对象dæ¥éæ¾qçèµæºè䏿¯delete
* `shared_ptr p(p2, d)` pæ¯æºè½æép2çä¸ä¸ªæ·è´ï¼åªæ¯p使ç¨dä½ä¸ºéæ¾èµæºç彿°
* `p.reset()` 妿pæ¯æä¸çä¸ä¸ªæåå½åå¯¹è±¡çæºè½æéï¼resetä¼éæ¾pç°æç对象ã
* `p.reset(q)` 妿built-in pointer q is passed, makes p point to q, otherwise make p null.
* `p.reset(q, d)` if d is supplied, will call d to free q otherwise uses delete to free q.
使ç¨å
建çæéç±»ååå§å`shared_ptr`æ¶ï¼å¿
é¡»ä½¿ç¨æ¾å¼çæé 彿°
```c++
shared_ptr p1 = new int(1024); // error: must use direct initialization
shared_ptr p2(new int(1024)); // ok: uses direct initialization
```
* ä¸è¦æ··å使ç¨å
建çæéç±»ååæºè½æé
å¦æåæ¶ä½¿ç¨äºå
建çæéç±»åï¼å½æºè½æééæ¾äºèµæºåï¼å
建çæéå¯è½è¿ä¼å¨å
¶ä»å°æ¹ä½¿ç¨åé
çèµæºãå æ¤å»ºè®®ä½¿ç¨`make_shared`æ¥å建æºè½æéï¼è䏿¯ç¨newçæ¹å¼ãä½¿ç¨æºè½æéæ¶ï¼ç´æ¥ä½¿ç¨å¼ä¼ éå°±å¯ä»¥äºã
```c++
void process(shared_ptr ptr)
{
// use ptr
} // ptr goes out of scope and is destroyed
int *x(new int(1024)); // dangerous: x is a plain pointer, not a smart pointer
process(x); // error: cannot convert int* to shared_ptr
process(shared_ptr(x)); // legal, but the memory will be deleted!
int j = *x; // undefined: x is a dangling pointer!
```
* å°½éé¿å
使ç¨`shared_ptr`çgetï¼å¦æå½æ°åæ°å¿
须为åå§çæéç±»åï¼åä¸å®ä¸è½å¨ç´æ¥éæ¾æéçèµæº
```c++
shared_ptr p(new int(42)); // reference count is 1
int *q = p.get(); // ok: but don't use q in any way that might delete its pointer
{ // new block
// undefined: two independent shared_ptrs point to the same memory
shared_ptr(q);
} // block ends, q is destroyed, and the memory to which q points is freed
int foo = *p; // undefined; the memory to which p points was freed
```
* reset å¯ä»¥è®©ä¸ä¸ªæºè½æé管çä¸ä¸ªæ°æé
The reset member is often used together with `unique` to control changes to the object shared among several `shared_ptrs` Before changing the underlying object, we check whether weâre the only user. If not, we make a new copy before making the change:
```c++
if (!p.unique())
p.reset(new string(*p)); // we aren't alone; allocate a new copy
*p += newVal; // now that we know we're the only pointer, okay to change this object
```
* å½è·³åºä¸ä¸ªå½æ°åï¼å½æ°å
é¨ç`shared_ptr`é½ä¼è¢«éæ¾ï¼å³ä½¿æ¯å¼å¸¸è·³åºäºå½æ°ã使¯å¦ææ¯å½æ°å
ç³è¯·çå
åï¼ç±äºå½æ°å¯è½å¨æ§è¡å
åçdeleteä¹å就已ç»è·³åºäºï¼å¯¼è´å
åæ³æ¼
##### ä½¿ç¨æºè½æéé¿å
å
åæ³æ¼æèµæºéæ¾
ä¾å¦ä½¿ç¨ä¸ä¸ªç½ç»åºæ¶ï¼è¿æ¥`connection`çææå½æ°ä¸æ²¡ææå¼è¿æ¥çå¤çé»è¾ï¼å¦ææä»¬å¿è®°æ§è¡æå¼è¿æ¥ç彿°ï¼å°±ä¼æèµæºæ²¡æéæ¾ã
```c++
struct destination; // represents what we are connecting to
struct connection; // information needed to use the connection
connection connect(destination*); // open the connection
void disconnect(connection); // close the given connection
void f(destination &d /* other parameters */)
{
// get a connection; must remember to close it when done
connection c = connect(&d);
// use the connection
// if we forget to call disconnect before exiting f, there will be no way to close c
}
```
è¿æ¶å¯ä»¥ä½¿ç¨èªå®ä¹ç`deleter`彿°æ¥å¼¥è¡¥è¿ä¸ªç¼ºé·ï¼è¿ä¸ªå½æ°ä½¿ç¨æºè½æéå
ç对象çæéä½ä¸ºåæ°ã
`void end_connection(connection *p) { disconnect(*p); } `
ä¿®æ¹ä½¿ç¨æºè½æéæ¥ç®¡çè¿æ¥
```c++
void f(destination &d /* other parameters */)
{
connection c = connect(&d);
shared_ptr p(&c, end_connection);
// use the connection
// when f exits, even if by an exception, the connection will be properly closed
}
```
å½pè¢«éæ¯æ¶ï¼å®ä¸ä¼å¯¹éé¢çæéæ§è¡deleteæä½ï¼èæ¯æ§è¡`end_connection`,ä»èä¿è¯äºè¿æ¥å¯ä»¥è¢«æ£ç¡®çéæ¾ãå³ä½¿ææåºç½ç»å¼å¸¸ï¼`end_connection`æ»æ¯å¯ä»¥è¢«ä¿è¯æ§è¡å°ã
##### ä½¿ç¨æºè½æéçé·é±
* ä¸è¦ä½¿ç¨å
建çæéåå§åæä½¿ç¨reset䏿¢ä¸ä¸ªæºè½æé对象
* ä¸è¦å¯¹æºè½æé`get()`è¿åçæé使ç¨deleteï¼è¦å®èªå·±éæ¾
* ä¸è¦ç¨`get()`çè¿å弿¥åå§åæresetå¦ä¸ä¸ªæºè½æé
* å¦æä½¿ç¨äº`get()`è¿åçæéï¼è¦çæè¿ä¸ªæéå¯è½è¢«å
¶ä»æºè½æéå·²ç»éæ¾äºã
* 妿è¦éæ¾é¤äºnewä¹å¤çèµæºï¼è®°å¾ä½¿ç¨ä¸ä¸ªèªå®ä¹çdeleter
##### unique_ptr
`unique_ptr`䏿¬¡åªè½ç®¡çä¸ä¸ªæé对象ã

åå§åä¸ä¸ª`unique_ptr`æ¶ï¼åªè½ä½¿ç¨æéæ¥åå§åã
ç±äº`unique_ptr`åªè½ç®¡çä¸ä¸ªå¯¹è±¡ï¼å æ¤å®ä¸æ¯ææ®éçæ·è´åèµå¼æä½ãåªè½ä½¿ç¨releaseæresetæ¥æ¹åä¸ä¸ª`unique_ptr`æåçæéã
```c++
unique_ptr p1(new string("Stegosaurus"));
unique_ptr p2(p1); // error: no copy for unique_ptr
unique_ptr p3;
p3 = p2; // error: no assign for unique_ptr
// transfers ownership from p1 (which points to the string Stegosaurus) to p2
unique_ptr p2(p1.release()); // release makes p1 null
unique_ptr p3(new string("Trex"));
// transfers ownership from p3 to p2
p2.reset(p3.release()); // reset deletes the memory to which p2 had pointed
```
if we do not use another smart pointer to hold the pointer returned from release, our program takes over responsibility for freeing that resource
```c++
p2.release(); // WRONG: p2 won't free the memory and we've lost the pointer
auto p = p2.release(); // ok, but we must remember to delete(p)
```
* ç¼è¯å¨æ¯ææ·è´æèµå¼ä¸ä¸ªå³å°éæ¯ç`unique_ptr`ï¼è¿æ ·`unique_ptr`å¯ä»¥ç¨äºå½æ°è¿åå¼
```c++
unique_ptr clone(int p) {
// ok: explicitly create a unique_ptr from int*
return unique_ptr(new int(p));
}
unique_ptr clone(int p) {
unique_ptr ret(new int (p));
// . . .
return ret;
}
```
* `auto_ptr`æ¯èçæ¬æ¯æçï¼åè½æ¯`unique_ptr`å°ï¼ä¸ä¸æ¯æå¨å®¹å¨ä¸ä½¿ç¨ã
* `unique_ptr`èªå®ä¹å é¤å¨çæ¹æ³ãè¦çé»è®¤çå é¤å¨ä¼å½±å`unique_ptr`ç±»åæé åresetï¼åæ¶ä¼å½±åå
³è容å¨ä¸çæ¯è¾æä½
```c++
// p points to an object of type objT and uses an object of type delT to free that object
// it will call an object named fcn of type delT
unique_ptr p (new objT, fcn);
void f(destination &d /* other needed parameters */)
{
connection c = connect(&d); // open the connection
// when p is destroyed, the connection will be closed
unique_ptr p(&c, end_connection);
// use the connection
// when f exits, even if by an exception, the connection will be properly closed
}
```
å
¶ä¸ä½¿ç¨äº`decltype`æ¥æå®å½æ°æéçç±»åï¼ç±äº`decltype(end_connection) `è¿åçæ¯ä¸ä¸ªå½æ°ç±»åï¼éè¦ä½¿ç¨*æ¥ææå®æ¯ä¸ä¸ªå½æ°æéã
##### weak_ptr
`weak_ptr`ä¸ä¼å¢å ä¸ä¸ªæéçå¼ç¨è®¡æ°ï¼å®å¿
须使ç¨ä¸ä¸ª`shared_ptr`æ¥åå§åãå³ä½¿æ`weak_ptr`æåçä¸ä¸ªå¯¹è±¡ï¼åªè¦shared_ptr`æåç对象计æ°ä¸º0ï¼è¿ä¸ªå¯¹è±¡è¿æ¯ä¼è¢«éæ¾ã

ç¨æ³å¦ä¸ï¼
```c++
auto p = make_shared(42);
weak_ptr wp(p); // wp weakly shares with p; use count in p is unchanged
```
ç±äº`weak_ptr`æåç对象å¯è½å·²ç»è¢«éæ¾äºï¼å æ¤éè¦ä½¿ç¨`lock`æ¥æ£æµå¯¹è±¡æ¯å¦è¿åå¨ã妿åå¨ï¼`lock`è¿åä¸ä¸ª`shared_ptr`ï¼ä»èä¿è¯ä½¿ç¨è¿ç¨ä¸è¿ä¸ªå¯¹è±¡ä¸ä¼è¢«éæ¾ã
```c++
if (shared_ptr np = wp.lock()) { // true if np is not null
// inside the if, np shares its object with p
}
```
举ä¾ï¼
```c++
// StrBlobPtr throws an exception on attempts to access a nonexistent element
class StrBlobPtr {
public:
StrBlobPtr(): curr(0) { }
StrBlobPtr(StrBlob &a, size_t sz = 0):wptr(a.data), curr(sz) { }
std::string& deref() const;
StrBlobPtr& incr(); // prefix version
private:
// check returns a shared_ptr to the vector if the check succeeds
std::shared_ptr<:vector>>check(std::size_t, const std::string&) const;
// store a weak_ptr, which means the underlying vector might be destroyed
std::weak_ptr<:vector>> wptr;
std::size_t curr; // current position within the array
};
```
第äºä¸ªæé 彿°ä½¿ç¨ä¸ä¸ª`StrBlob`对象çå¼ç¨ï¼å¹¶å°å
¶ä¸ç`shared_ptr`æådataåå§åäº`wptr`
```c++
std::shared_ptr<:vector>>
StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
auto ret = wptr.lock(); // is the vector still around?
if (!ret)
throw std::runtime_error("unbound StrBlobPtr");
if (i >= ret->size())
throw std::out_of_range(msg);
return ret; // otherwise, return a shared_ptr to the vector
}
```
ç±äº`weak_ptr`ä¸ä¼å¢å å¼ç¨è®¡æ°`check`彿°ä¸å
å¤æå¯¹è±¡æ¯å¦åå¨ï¼ç¶åè¿åäºæåvectorç`shared_ptr`
è§£å¼ç¨çå®ç°
```c++
std::string& StrBlobPtr::deref() const
{
auto p = check(curr, "dereference past end"); // p is a shared_ptr to the vector
return (*p)[curr]; // (*p) is the vector to which this object points
}
// prefix: return a reference to the incremented object
StrBlobPtr& StrBlobPtr::incr()
{
// if curr already points past the end of the container, can't increment it
check(curr, "increment past end of StrBlobPtr");
++curr; // advance the current state
return *this;
}
```
ç±äºè¿ä¸ªç±»`StrBlobPtr`访é®äº`StrBlob`çæåï¼éè¦è®¾ç½®ä¸ºåå
ç±»
```c++
// forward declaration needed for friend declaration in StrBlob
class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
// other members as in § 12.1.1 (p. 456)
// return StrBlobPtr to the first and one past the last elements
StrBlobPtr begin() { return StrBlobPtr(*this); }
StrBlobPtr end() { auto ret = StrBlobPtr(*this, data->size());return ret; }
};
```
### 12.2 卿æ°ç»
#### new and delete[]
使ç¨`type* p = new type[n]`å¾å°çæéç±»å并䏿¯æ°ç»ç±»åï¼å æ¤ä¸è½å¨å¾å°ç对象使ç¨`begin`å`end`.é»è®¤æ
åµä¸ï¼ä½¿ç¨newåé
çå
åæ è®ºæ¯åä¸ªå¯¹è±¡è¿æ¯æ°ç»å¯¹è±¡ï¼é½ä¼è¢«åå§åãå¯ä»¥ç´æ¥è°ç¨æé 彿°åå§å对象ã
```c++
string* pStr = new string[10]();
// c++11
int *pia3 = new int[10]{0, 1, 2, 3, 4, 5, 6, 7};
// vc2013 does not support this feature
//string *psa3 = new string[3]{"a", "an", "the"};
// å¯ä»¥å建ä¸ä¸ª0个å
ç´ çæéï¼å¾å°çæéå¯ä»¥ä¸0è¿è¡+æ-ï¼ä¹å¯ä»¥ä¸èªå·±è¿è¡åæ³å¾å°0
char *cp = new char[0]; // ok: but cp can't be dereferenced
delete[] pStr;
// up points to an array of ten uninitialized ints
unique_ptr up(new int[10]);
up.release(); // automatically uses delete[] to destroy its pointer
for (size_t i = 0; i != 10; ++i)
up[i] = i; // assign a new value to each of the elements
// to use a shared_ptr we must supply a deleter
shared_ptr sp(new int[10], [](int *p) { delete[] p; });
sp.reset(); // uses the lambda we supplied that uses delete[] to free the array
// shared_ptrs don't have subscript operator and don't support pointer arithmetic
for (size_t i = 0; i != 10; ++i)
*(sp.get() + i) = i; // use get to get a built-in pointer
```
æ°ç»æéä¸çå
ç´ æ¯éåºéæ¾çï¼å³æåä¸ä¸ªå
ç´ çææææ©è¢«æ§è¡ã
* æºè½æé坹卿æ°ç»å
åçæ¯æå¾å·®ï¼å¯ä»¥å¿½ç¥ä¸ä½¿ç¨
æ ååºä¸çæºè½æéåªæ`unqiue_ptr`æ¯æå¨æåé
æ°ç»ãè`shared_ptr`éè¦èªå·±å®ç°`deleter`,ä¹ä¸æ¯æä¸æ 访é®çæ¹å¼ï¼åªè½æå
鍿éååºæ¥ï¼åç¨ç´¢å¼æ¥è®¿é®.èæºè½æéæä¾çæ¥å£é½ä¸è½ä½¿ç¨ï¼å 为解å¼ç¨å¾å°çæ¯ä¸ä¸ªæ°ç»ï¼è䏿¯ä¸ä¸ªå
·ä½çæ°ç»å
ç´ ã
#### Allocator
ç±äºnewæå
ååé
å对象æé ç»å®å¨ä¸èµ·ï¼èdeleteæå
å鿾忿ç»å®å¨ä¸èµ·ï¼èæäºæ¶åæä»¬åªæ¯å¸æåé
å
å空é´ï¼çéè¦çæ¶åæå»åå§åå¯¹è±¡ï¼æé«æçã
ä¾å¦ä½¿ç¨ä¸ä¸ªstringæ°ç»ä¿åç¨æ·è¾å
¥çæ°æ®ï¼è卿°ç»newçæ¶åï¼æ°ç»ä¸çæ¯ä¸ä¸ªstringé½è¢«åå§åäºï¼èåé¢ç¨æ·è¾å
¥çå¼è¿ä¼æå·²ç»åå§åè¿çstringå¨è¦ç䏿¬¡ï¼ç¸å½äºä¸ä¸ªå¯¹è±¡è¢«åäºä¸¤æ¬¡ã
allocatorå¨``ä¸å®ä¹ãå®å¯ä»¥åªåé
å
åï¼èä¸åå§å对象ã宿¯ä¸ä¸ªæ¨¡æ¿ç±»ï¼ä½¿ç¨æ¶éè¦æå®ä¸ä¸ªå®åé
å
åçç±»åãå
å«ä»¥ä¸åºæ¬æä½

```c++
int size = 5;
allocator strAlloc;
// size of memory is size*sizeof(string), no constructor is called
auto const p = strAlloc.allocate(size);
auto q = p; // memory is still cdcdcdcd on windows
// construct object with constructor of string
strAlloc.construct(q++);
strAlloc.construct(q++, 10, 'c'); // "cccccccccc"
strAlloc.construct(q++, "hi"); // "hi"
cout << *(p + 1) << endl; // output the second item "cccccccccc"
cout << *q << endl; // error, not initialize
// call the destructor for each item
while (q != p)
{
strAlloc.destroy(--q);
}
// 使ç¨ç®æ³æ¥å£åå§å
vector vStr;
vStr.push_back("from vector");
// å¨VC2013ä¸ç¼è¯è¯¥è¡æ¶ä¼æç¤º error C4996: 'std::_Uninitialized_copy0': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'ãéè¦å¨ç¼è¯é项çå½ä»¤è¡åæ°ä¸å ä¸-D_SCL_SECURE_NO_WARNINGSï¼æè½ç¼è¯éè¿
// ä»å¦ä¸ä¸ªvector䏿·è´å
ç´ ç±»åå§å卿å
åï¼è¿å弿åä¸ä¸ä¸ªå
ç´
auto q2 = uninitialized_copy(vStr.begin(), vStr.end(), p + 3);
// åå§åå¤ä¸ªç¸åå¼
uninitialized_fill_n(q2, 1, "low");
cout << *(p + 3) << endl; // from vector
cout << *(p + 4) << endl; // low
// do not forget to destroy
strAlloc.destroy(p + 3);
strAlloc.destroy(p + 4);
// free the memory, the point and size must right
strAlloc.deallocate(p, size);
```
* allocatoræ¯æçç®æ³ï¼ä½¿ç¨ä»¥ä¸æ¥å£å¯ä»¥å¾æ¹ä¾¿ç对å
ååå§ååéæ¾ï¼èä¸ç¨ä¸ä¸ªä¸ä¸ªæ§è¡åå§å

## Part III
#### 13.3 Swap
ä¸ä¸ªæå¨æåé
èµæºçç±»ä¸è¬ä¼å®ä¹èªå·±çswap彿°ï¼å¨stlçç®æ³éè¦å¯¹å¯¹è±¡è¿è¡æåºæ¶ï¼äº¤æ¢ä¸¤ä¸ªå
ç´ æ¯ä½¿ç¨std::swap伿髿çã妿ä¸ä¸ªç±»å®ä¹äºèªå·±çswap彿°ï¼åºå°±ä¼ä¼å
å¹é
å°å½åç±»çswapè䏿¯stdçã
ä¸è¬æ
åµä¸stdçswapå¯è½ä¼æ§è¡ä¸æ¬¡æ·è´å2次èµå¼æä½ãä¾å¦HasPtrå
鍿ä¸ä¸ªstring对象çæéï¼å¨æ·è´æé æ¶ï¼å°±ä¼ç»tempå
é¨åé
ä¸ä»½stringçå
åç¨æ¥æ·±æ·è´ï¼ä½å®é
ä¸æä»¬åªæ¯éè¦äº¤æ¢v1åv2å
é¨string对象çæéå³å¯ï¼æ ¹æ¬ä¸éè¦é£æ¬¡å¤ä½çå
ååé
ã
```c++
HasPtr temp = v1; // make a temporary copy of the value of v1
v1 = v2; // assign the value of v2 to v1
v2 = temp; // assign the saved value of v1 to v2
```
é常ä¸ä¸ªç±»swap彿°å¦ä¸å®ä¹ï¼swap彿°è¢«å£°æä¸ºfriendï¼è¿æ ·å¯ä»¥è®¿é®å°ç±»çç§ææååéãåæ¶ç±äºswapè¿éæ¯ä¸ºäºä¼åæ§è½ï¼å æ¤å®ä¹ä¸ºinlineçã彿°å
é¨è°ç¨stdçswapæ¥ç´æ¥äº¤æ¢ä¸¤ä¸ªå¯¹è±¡æéæåpsã
```c++
class HasPtr
{
public:
// to access the private member
friend void swap(HasPtr&, HasPtr&);
public:
HasPtr(const std::string &s = std::string()) :
ps(new std::string(s)), i(0) { }
// each HasPtr has its own copy of the string to which ps points
HasPtr(const HasPtr &p) :
ps(new std::string(*p.ps)), i(p.i) { }
HasPtr& operator=(const HasPtr &);
~HasPtr() { delete ps; }
private:
std::string *ps;
int i;
};
inline
void swap(HasPtr &lhs, HasPtr &rhs)
{
using std::swap;
swap(lhs.ps, rhs.ps); // swap the pointers, not the string data
swap(lhs.i, rhs.i); // swap the int members
}
```
éè¦æ³¨æå¨è°ç¨æ¶ï¼ä¸è½ç¨std::swap()ï¼é£æ ·å°±æ æ³è°ç¨ç±»èªå·±å®ä¹çswapäºã
> If there is a type-specific version of swap, that version will be a better match than the one defined in std.
##### copy and swap
妿ä¸ä¸ªç±»å®ä¹äºèªå·±çswap彿°ï¼é常å®ä¼ç¨swap彿°æ¥å®ä¹èµå¼æä½ãéè¿å°å·¦å¼ä¸å³å¼çä¸ä¸ªæ·è´è¿è¡äº¤æ¢ã
注æè¿éç忰䏿¯å¼ç¨ï¼èæ¯å¼ï¼è¿æ ·å¨ä¼ éå
¥åæ¶ä¼æ=å³è¾¹ç对象æ·è´ä¸ä»½ä¸ºrhsãå¨å®ç°å
é¨å°å·¦å¼çæå䏿·è´ç临æ¶åéçæå交æ¢ï¼ä»èæå³å¼çå
容å¤å¶å°äºå·¦å¼éé¢ï¼èå·¦å¼åæ¥å
é¨çæéå¨ä¸´æ¶åérhséåºå½æ°æ¶éæ¾ã
```c++
// note rhs is passed by value, which means the HasPtr copy constructor
// copies the string in the right-hand operand into rhs
HasPtr& HasPtr::operator=(HasPtr rhs)
{
// swap the contents of the left-hand operand with the local variable rhs
swap(*this, rhs); // rhs now points to the memory this object had used
return *this; // rhs is destroyed, which deletes the pointer in rhs
}
```
è¿ä¸ªå®ç°æä¸¤ä¸ªå¥½å¤ï¼
1. ä¸ç¨å¤ææ¯å¦æ¯èªæèµå¼äºï¼å 为å³å¼è¢«æ·è´äºä¸ä»½
2. å¼å¸¸å®å
¨ï¼copyæé çè¿ç¨ä¸new失败æåºå¼å¸¸å¨ä¿®æ¹å·¦å¼ä¹ååçã