C++自修入門實境秀、C++ Primer 5版研讀秀 76/ ~ v12動態記憶體(dynamic memory)12.1.1. The s...





頁449

Chapter 12. Dynamic Memory

動態記憶體

Word VBA 漢字部件列出與部件構字列出程式碼修訂

OK 測試成功 23:00 https://snipsave.com/oscarsun72/#/snippet/bJFKWz2tc2Ea2oYNh7

漢字華語文部件模組程式碼 Bujian Components

⑦先抓動詞 ⑧找對主詞

什麼東東動態dynamic? 記憶體配置的情形是動態的,不是一配置就不變動的

是與static靜態相對 55:00

56:50

前面才有文字轉換程式,這裡是文字查詢程式

Section 12.3 Using the Library: A Text-Query Program

12.3使用程式庫:一個文字查詢程式

本章主題與「生命週期(lifetime)」脫離不了干係

The programs we’ve written so far have used objects that have well-defined lifetimes.

我們目前寫過的程式都使用生命週期定義明確的物件。

生命週期都幫我們定義、安排得好好地的了,就像父母襁褓中的孩子,都不用擔心什麼。這章則是要長大獨立,自己安排前程了

全域的物件其生命週期則是與應用程式相終始的:

Global objects are allocated at program start-up and destroyed when the program ends.

區域變數與自動物件,是在程式執行進入它被定義的區塊時被創建,而在離開這個區塊時被註銷:

Local, automatic objects are created and destroyed when the block in which they are defined is entered and exited.

Local static objects are allocated before their first use and are destroyed when the program ends.

而區域的靜態物件則是在執行到它們之前被創建(配置),而在整個應用程式結束時才會被註銷

除了提供自動物件與靜態物件,C++還讓我們能夠自己動態地配置(創建暨註銷)物件

所謂動態配置物件,和自動物件最大的不同在於,自動物件在生命週期結束後會「自動」註銷,釋放記憶體,可是動態配置的物件(dynamically allocated object)卻必須明確聲明要被註銷才會被註銷而釋出記憶體

1:26:00

為了要讓動態物件能安全地被釋放,因此才有智慧指標(smart pointer)的設置

可見智慧指標與動態配置的物件的息息相關的

Properly freeing dynamic objects turns out to be a surprisingly rich source of bugs.

要如何正確釋放動態物件被發現是一種非常常見的臭蟲來源。→適時地釋放動態物件卻會引發許多意想不到的錯誤。

To make using dynamic objects safer, the library defines two smart pointer types that manage dynamically allocated objects.

Smart pointers ensure that the objects to which they point are automatically freed when it is appropriate to do so.

某些智慧指標能確保它們所指的物件會在適當時被自動釋放。中文版又翻錯了:原文並無「某些」!

it 代 「appropriate to do so」這件事

turns out……source 被發現是……來源→引發出

頁450

1:39:55

目前為止我們寫過的程式只用到靜態static及堆疊stack記憶體

有的用到靜態記憶體,有的則用到堆疊的

靜態記憶體(staic memory)是給以下物件用的:

1. 區域靜態物件(頁205)

2. 類別的靜態資料成員(頁300)

3. 任何在函式外定義的變數(定義在任何函式外的變數)

堆疊記憶體(stack memory)則是給定義在函式內的非靜態物件

配置在靜態與堆疊記憶體的物件都是由編譯器自動建構與銷毀的(創建與註銷)

除了靜態或堆疊記憶體,每個程式program都還有一個集區(pool)的記憶體可用。

1:52:50

目前所學的記憶體區域有以下3種:

靜態static

堆疊stack

集區pool

1:56:20

也就是作業系統在管理應用程式時是至少配置了這3種記憶體區域供其差遣

集區記憶體(pool of memory)是當作free store或者heap來使用的

這個記憶體被稱作自由存放區(free store)或heap(堆積)。

堆積→恐怕還不如翻成堆棧、雜物間

自由存放區→隨意安放、隨便放

可見這個「集區記憶體」卻是本章動態配置的物件的重點,動態物件就是被放在這個區域的

Programs use the heap for objects that they dynamically allocate—that is, for objects that the program allocates at run time.

The program controls the lifetime of dynamic objects; our code must explicitly destroy such objects when they are no longer needed. 不見題目只見關鍵字

可見動態配置物件就是在執行階段配置的物件

2:9:00

Warning:

Although necessary at times, dynamic memory is notoriously tricky to manage correctly.

雖然有時是必要的,但動態記憶體是惡名昭彰的難以正確管理。

這在翻什麼?!完全看不動

⑤添字還原 ⑧找對主詞 必要什麼啊?

由上下文(前後文) 來判斷應指「正確」地「管理」「動態記憶體」

動態記憶體(dynamic memory)的適當管理是非常不容易的

也因此,有效且正確地管理動態記憶體便是本章討論的重點所在

2:12:4

12.1. Dynamic Memory and Smart Pointers

動態記憶體與智慧指標

C++是透過兩個(一對的pair)運算子new、delete來處理動態物件(dynamic object)及對動態記憶體(dynamic memory)的管理

In C++, dynamic memory is managed through a pair of operators:

new, which allocates, and optionally initializes, an object in dynamic memory and returns a pointer to that object; and

delete, which takes a pointer to a dynamic object, destroys that object, and frees the associated memory.

2:18:00

要適時地釋放動態記憶體是非常困難的

a memory leak 記憶體缺陷

記憶體洩漏(memory leak)

這個「漏」,如佛家的「有漏」的漏。表有缺陷,不完美(完封)——因為管理不當,而被濫用的(該釋放而不放、該歸公的不歸公,就被姦私挪用、侵佔去了) 4:16:00

還有指標指向那個記憶體位址就不當釋放該處的記憶體;如果這個指標還有作用,那麼若釋放了它指向的記憶體位址,則該指標就會變成無效的了

為了更有效且安全地對動態記憶體(dynamic memory)進行妥善地管理,C++11的新標準就引進了2種智慧指標型別(smart pointer type)供我們應用——來管理、操縱動態物件(dynamic object)

智慧指標(smart pointer)和一般指標並沒有什麼不同,只是它會自動解銷(註銷、銷毀、刪除deletes)它指向的動態物件;這是其他一般的指標絕對做不到的with the important exception。

新的程式庫定義的兩種智慧指標,其差異在於differ in 它們是如何處理它所指的底層物件的

shared_ptr

這種指標允許多個指標指向同一個動態物件,所以叫「shared」 ⑧找對主詞 share什麼?和其他的指標share,不是一個指標獨佔的!所以相對的就叫「unique」:

unique_ptr

這種指標是獨佔性質的佔有慾很強,對於它所指向的動態物件,是不容許它人來染指的(其所指之物件,乃其禁臠也)所以unique_ptr可以翻成禁臠指標或不容染指指標,或私有財產指標

而shared_ptr就能翻成,共享指標,或藏富天下指標,或天下為公指標,或公有財產指標

weak_ptr

因為2種智慧指標都是型別,所以新的程式庫也隨之定義了一個叫做「weak_ptr」的型別/類別庫(class)

這種型別是一種weak的參考,參考到一個由shared_ptr共享指標(公有財產指標)所管理的物件

弱參考(weak reference)



以上3種指標都定義在memory標頭檔中

12.1.1. The shared_ptr Class

2:47:40

智慧指標也是模板型別(template type),和vector一樣

因此在定義(建構)一個智慧指標時我們必須提供這個智慧指標能夠指向的物件、其型別是什麼

和定義vector的寫法類似,一樣是將此型別的名稱寫在角括弧中,而這個角括弧是緊跟在該智慧指標型別名稱的後頭的

shared_ptr<string> p1; // shared_ptr that can point at a string

shared_ptr<list<int>> p2; // shared_ptr that can point at a list of ints

2:55:05

頁451

若是一個預設初始化的智慧指標,會是一個空的指標 holds a null pointer

在後面頁464我們會再討論智慧指標的其他初始化方式

In § 12.1.3 (p. 464), we’ll cover additional ways to initialize a smart pointer.

在§12.1.3中,我們會涵蓋初始 化一個智慧指標的其他方式。→在§12.1.3中,會涵蓋初始化智慧指標其他方式這方面的內容。

哪有人家這樣用「涵蓋」的!涵蓋主詞不能是人,要是內容! ⑧找對主詞 邏輯、語意之不諳即若此!



3:5:17

使用一個智慧指標和使用普通指標非智慧指標是類似的

解參考智慧指標也是回傳它指向的物件

3:7:00

When we use a smart pointer in a condition, the effect is to test whether the pointer is null:

當我們在一個條件中使用一個智慧指標,效果就等於測試該指標是否為null :

effect在這裡應該翻成「目的、用途、為的」

condition條件式

在條件式使用一個智慧指標,為的就是測試看看它是不是個空的指標

一個「目的」,不就是「最後的效果(結果)」嗎?

// if p1 is not null, check whether it's the empty string

if (p1 && p1->empty())

*p1 = "hi"; // if so, dereference p1 to assign a new value to that string

null回傳的是「0」,所以在條件式中,就是false

3:13:20

表12.1列出了 shared_ptr和unique_ptr共用common的運算

表12.2則是shared_ptr獨有的運算





make_shared 函式

前面map有make_pair函式,這裡有make_shared

3:19:20 對動態記憶體(dynamic memory)的使用和配置最安全的方式就是調用程式庫的make_shared函式 定義在memory標頭檔中

這個函式的作用就是配置並初始化一個動態記憶體中的物件,並且回傳一個shared_ptr型別的智慧指標來指向它

3:41:55

make_shared<T>(args)

和使用模板類別一樣,也要用角括弧來指定我們要創建的動態物件的型別是什麼

3:49:50

// shared_ptr that points to an int with value 42

shared_ptr<int> p3 = make_shared<int>(42);

// p4 points to a string with value 9999999999

shared_ptr<string> p4 = make_shared<string>(10, '9');

// p5 points to an int that is value initialized (§ 3.3.1 (p. 98)) to 0

shared_ptr<int> p5 = make_shared<int>();

就像循序容器的emplace成員(§9.3.1),make_shared也使用其引數來建構給定型別的一個物件。

如果調用make_shared函式卻沒有提供引數來建構初始化動態物件,那麼就會是值初始化(value initialize)

Copying and Assigning shared_ptrs

當我們在對shared_ptr物件作複製copy或指定assign的時候,每個shared_ptr都會持續追蹤有多少個shared_ptr指向與它一樣的動態物件。



頁452

3:17:00 3:26:50

Table 12.1. Operations Common to shared_ptr and unique_ptr

表 12.1 : shared_ptr 和 unique_ptr 共通的運算

shared_ptr<T> sp

unique_ptr<T> up 可以指向型別為T的物件的null智慧指標。

P 使用p作為條件,如果p指向一個物件就為true。

*p 解參考p來取得p所指的物件。

p->mem (*p).mem的同義詞。

p.get() 回傳P中的指標。使用時請小心,回傳的指標所指的物件會在智慧指標刪除它的時候消失。

swap(p,q) p.swap(q) 對調p與q中的指標。守真按:對調p與q此二變數所載(所存放)的指標

Swaps the pointers in p and q.

4:5:00

shared_ptr 參考計數(reference count)。

一旦shared_ptr的參考計數歸零的時候,它就會釋放註銷它所管理物件

Once a shared_ptr’s counter goes to zero, the shared_ptr automatically frees the object that it manages:

auto r = make_shared<int>(42); // int to which r points has one user

r = q; // assign to r, making it point to a different address

// increase the use count for the object to which q points

// reduce the use count of the object to which r had pointed

// the object r had pointed to has no users; that object is automatically freed

shared_ptrs Automatically Destroy Their Objects ...

解構器(destructor)

When the last shared_ptr pointing to an object is destroyed, the shared_ptr class automatically destroys the object to which that shared_ptr points. It does so through another special member function known as a destructor.

類似於建構器,每個類別都有一個解構器。就像建構器會控制初始化,解構器會控制該類別型別的物件被摧毀時會發生什麼事。

所以每個類別的建構器是供給智慧指標型別(smart pointer type)來調用的

頁453

3:30:10

Table 12.2. Operations Specific to shared_ptr

表12.2 : shared_ptr專屬的運算

make_shared<T>(args) 回傳一個shared_ptr指向型別為T的一個動態配置的物件。使用 args來初始化那個物件。

shared_ptr<T> p(q) p是shared_ptr q的一個拷貝,會遞增q中的計數。q中的指標必須能夠轉換為T* ( §4.11.2,頁162)。

p = q p與q是存放著能夠轉換成彼此的指標的shared_ptr。遞減p的參考計數並遞增q的計數;如果p的計數降為0,就刪除p既有的 記憶體。

p.unique() 如果p.use_count()是一,就回傳true,否則為false。

p.use_count() 回傳與p共用的物件數;可能會是緩慢的運算,主要用於除錯。

4:28:10

至於shared_ptr的解構器則不是摧毀什麼,而是將它所指向的物件數目做遞減運算而已(即每調用一次則將其參考計數(reference count)減1);一旦參考計數歸零時,它才呼叫所指物件類別的解構器來將該物件解構並釋放記憶體資源

The destructor for shared_ptr decrements the reference count of the object to which that shared_ptr points. If the count goes to zero, the shared_ptr destructor destroys the object to which the shared_ptr points and frees the memory used by that object.

看似shared_ptr的解構器在摧毀物件,實則是它調用它要摧毀的物件類別中的建構器來解構該物件

...and Automatically Free the Associated Memory

…並自動釋放關聯的記憶體

原來前面「shared_ptrs Automatically Destroy Their Objects .. ...and Automatically Free the Associated Memory.」是要與此句並看的

shared_ptr智慧指標的這種特性,對動態記憶體(dynamic memory)的使用,幫助很大



頁454

4:44:00



這就是所謂的記憶體洩漏(leak),就類似於shared_ptr殘留:

Because memory is not freed until the last shared_ptr goes away, it can be important to be sure that shared_ptrs don’t stay around after they are no longer needed. The program will execute correctly but may waste memory if you neglect to destroy shared_ptrs that the program does not need.

One way that shared_ptrs might stay around after you need them is if you put shared_ptrs in a container and subsequently 接著reorder the container so that 為了是、因為you don’t need all the elements. You should be sure to erase shared_ptr elements once you no longer need those elements.

後續你重新排序了該容器,使得你不再需要所有的元素。

5:10:00 5:16:30

找適合的檔案總管軟體

FreeCommanderXE-32-public_portable

Q-Dir



5:33:20

將shared_ptr當作元素放在容器中,只要用不上的,就要記得把它erase清除

Classes with Resources That Have Dynamic Lifetime

其資源具有動態生命週期的類別

會用到動態記憶體(dynamic memory)的應用程式通常有著以下的目的:

1.不知要用上多少個物件

容器類別通常就是這種情形

2.不知道要用到的物件的確切型別

在第15章會看到這種實例

3.想在不同物件間分享資料

本節則會定義一個類別,它想在不同物件間共享底層的資料,而使用動態記憶體

5:53:20

目前為止,我們用過的類別所配置的資源存在的時間就跟對應的物件一樣長。

5:58:00

有些類別配置資源與vector不同,它是以獨立於原物件存在的情境與條件下來配置的,它的生命週期並不隨其物件而生滅

頁455

6:1:10

共享資源的物件,在其中某些註銷時,不能片面地unilaterally隨之註銷其底層並用的資源(記憶體配置)就是不能片面解約的意思



originally created 原生的

6:7:00

Note:

One common reason to use dynamic memory is to allow multiple objects to

share the same state.

使用動態記憶體的一個常見的理由是允許多個物件共用相同的狀態。

也就是讓生命週期有更加彈性、客製化、自訂的選擇,而不是如自動物件一般,自動銷毀、消亡 Have Dynamic Lifetime 就是更具彈性地

6:10:28

Defining the StrBlob Class

頁456

initializer_list<string> (§ 6.2.6, p. 220).

8:7:22

class StrBlob

{

public:

typedef std::vector<std::string>::size_type size_type;//以型別別名定義型別成員(type member)

StrBlob();//預設建構器,只有宣告,沒有定義(實作)

StrBlob(std::initializer_list<std::string> il);//帶了一個initializer_list<string>參數的建構器,也只有宣告,沒有定義(實作)

size_type size() const { return data->size(); }//常值的const成員函式

bool empty() const { return data->empty(); }//常值的const成員函式

// add and remove elements

void push_back(const std::string &t) { data -

> push_back(t); }

void pop_back();//pop_back//只有宣告,沒有實作(定義)

// element access

std::string &front();

std::string &back();



private:

std::shared_ptr<std::vector<std::string>> data;

// throws msg if data[i] isn't valid

void check(size_type i, const std::string &msg) const; //常值的const成員函式,只有宣告

};



8:11:00

Inside the class we implemented the size, empty, and push_back members.

These members forward their work through the data pointer to the underlying vector. For example, size() on a StrBlob calls data->size(), and so on.

StrBlob Constructors

8:16:11

StrBlob建構器的定義(實作)

StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}

StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {}//用il來作為make_shared引數,就不是空的vector了

:和{}之間的部件,就是建構器初始器串列(constructor initializer list)

用make_shared來建構一個動態配置的容器vector物件

8:31:30

接受一個initializer_list的建構器會將其參數傳到對應的vector建構器(§ 2.2.1,頁43、97、98)。 那個建構器會藉由拷貝串列中的值來初始化vector的元素。

頁457

Element Access Members

元素存取成員

存取元素的成員函式

8:33:50

頁43

WARNING: 初始化並非指定。初始化發生在一個變數於創建之時被賦予一個值的時候。指定則會抹消一個物件目前的值,並以一個新的值取代之。第76集 8:37:55

串列初始化

這個語言定義了數種形式的初始化

我們可以使用下列四種不同方式的任何一種來定義一個名為units_sold的int變數,並將之 初始化為0:

int units_sold = 0;

int units_sold = {0};

int units_sold{0};

int units_sold(0);





由於我們會在§3.3.1(頁97、98)中學到的理由,這種形式的初始化被稱為串列初始化(list initialization)。

與內建型別的變數一起使用時,這種形式的初始化會有一個重要的特性:如果初始器可能導致資訊的損失,編譯器就不會讓我們串列初始化內建型別的變數:第76集 8:46:00

然而,如我們會在第16章中看到的,這種初始化有可能會不經意的發生。 我們會在§3.2.1(頁84)和§3.3.1(頁97)中更深入討論初始化的這些形式。

預設初始化

第76集 9:26:40

如果我們定義一個變數的時候不使用初始器,該變數就會以預設的方式被初始化(default initialized)。這種變數會被賦予「預設(default)」值。這個預設值會是什麼,則取決於該變數的型別,也可能還取決於該變數是在何處定義的。

Variables defined outside any function body are initialized to zero.

With one exception, which we cover in § 6.1.1 (p. 205), variables of built-in type

defined inside a function are uninitialized. The value of an uninitialized variable of

built-in type is undefined (§ 2.1.2, p. 36).

It is an error to copy or otherwise try to access the value of a variable whose value is undefined.

一個內建型別物件的值,若未明確初始化,就要以它是在何處定義的來決定。定義在任何函式主體(function body)之外的變數會被初始化為零。只有一個例外(會涵蓋在§ 6.1.1中;守真按:應就是Local static Objects),也就是在一個函式內定義的內建型別變數都是未初始化的(uninitialized)。

頁44

Each class controls how we initialize objects of that class type. In particular, it is up to the class whether we can define objects of that type without an initializer. If we can, the class determines what value the resulting object will have.

2.2.2. Variable Declarations and Definitions

2.2.2變數宣告與定義

第76集 9:47:00

個別編譯(separate compilaton)

為了讓程式能以符合邏輯的方式分割寫成,C++支援常被稱為個別編譯(separate compilaton)的功能。個別編譯能讓我們將程式分割為數個檔案,其中每一個都能獨立編譯。



3.2. Library string Type

字串(string)是一個可變長度的字元序列

3.2.1. Defining and Initializing strings

一個類別class對它的物件對象object的初始化可以有多重的定義(第76集9:0:10即建構器(constructor)及建構器初始器串列(constructor initializer list)的概念)





Table 3.1. Ways to Initialize a string

表3.1 :初始化一個string的方式

string s1 預設初始化,s1是空字串。

string s2(s1) s2是s1的一個拷貝。

string s2 = s1 等同於s2(s1),s2是s1的一個拷貝。

string s3("value") s3是那個字串字面值的一個拷貝,不包括null字元。

string s3 ="value" 等同於s3("value"),s3是那個字串字面值的一個拷貝。

string s4(n, 'c') 以字元'c'的n個拷貝初始化s4。

第76集 8:56:40





頁98

List Initializing a vector

vector的串列初始化

串列初始化(list initialize)一個vector

串列初始化(list initialization)一定要用大括號,不能用圓括號:

We cannot supply a list of initializers using parentheses:

因為圓括號就相當於cope(=),所以用圓括號來direct直接初始化,圓括號中只能有一個初始器的值

Creating a Specified Number of Elements

配置/建置指定數目的元素

Value Initialization (對於元素)值的初始化

值初始化(value initialize)

第76集9:55:30當省略了部分初始器時

我們通常可以省略那個值,只提供一個大小。在這種情況中,程式庫會為我們創建一個value-initialized(值初始化)的元素初始器。這個程式庫產生的值會被用來初始化容器中的每個元素。元素初始器的值取決於儲存在vector中元素的型別。

如果vector存放的元素有內建型別,例如int,那麼這個元素初始器就會有0的值。如果那些元素的型別是某種類別型別,例如string,那麼元素初始器本身就會被預設初始化:

頁99

Table 3.4. Ways to Initialize a vector

第76集 9:19:40

表3.4 :初始化一個vector的方式

vector<T> v1 持有的物件之型別為T的vector。預設初始化,v1是空的。

vector<T> v2(v1) v2有v1中每個元素的拷貝。

vector<T> v2 = v1 等同於v2 (vl),v2是vl中元素的一個拷貝。

vector<T> v3 (n, val) v3 有值為 val 的 n 個元素。

vector<T> v4 (n) v4 有一個 value-initialized 物件的 n 個拷貝。

vector<T> v5{a,b,c …… } v5有跟初始器同樣數目的元素;元素是由對應的初始器所初始化。

vector<T>v5= {a,b,c……} 等同於前面的 v5{a,b,c ……}。





6.2.6. Functions with Varying Parameters

6.2.6帶有不定參數的函式

動態參數的函式 第76集 6:33:40

不定參數的函式

1:15:30

1:18:30新標準提供了二種定義不定數量的參數函式的方法:

The new standard provides two primary ways to write a function that takes a varying number of arguments:

1.參數型別同:如果所有參數都有一致的型別,則我們可以透過程式庫型別 initializer_list 來傳遞引數

2.參數型別不一:如果參數間的型別不一致,則

we can write a special kind of function, known as a variadic template, which we’ll cover in § 16.4 (p. 699 ).

variadic template (參數可變的模板)

3.C++還有一種特殊的參數型別——ellipsis,

ellipsis(省略符號)

that can be used to pass a varying number of arguments.也可以用來傳遞不定數量的參數

ellipsis parameters 省略參數

這種機制(運用)應該只在需要與C語言的函式作互動的時候才用上

值得注意的是,這項機能通常只應該用於需要與C 函式界接的程式中。

1:29:33

initializer_list Parameters

initializer_list就是一種陣列:

initializer_list是一個程式庫型別,用來表示其中的值都是指定型別的一種陣列

這個型別定義於initializer_list標頭中

第76集 6:40:10 6:49:00

Table 6.1. Operations on initializer_lists

表 6.1 : initializer_list 上的運算

initializer_list<T> lst; 預設初始化;型別為T的元素所成的一個空串列。

initializer_list<T> lst{a,b,c...}; lst有跟初始器(initializers)數目一樣多的元素;這些元素是對應的初始器的拷貝。串列中的元素是const。

lst2(lst)

lst2 = lst 拷貝或指定一個initializer_list並不會拷貝串列中的元素。拷貝之後,原來的跟拷貝的會共用那些元素。

Copying or assigning an initializer_list does not copy the elements in the list. After the copy, the original and the copy share the elements.

lst.size() 串列中的元素數目。Number of elements in the list.

lst.begin()

lst.end() 回傳指標指向lst中的第一個元素和超過最後元素一個位置的地方。Returns a pointer to the first and one past the last element in lst.



前提是要參數型別一致

1:37:00

copy or assign initializer_list 並不copy 來源的元素,而是與來源共享其元素

1:39:00

頁221

initializer_list 和 vector類似,皆為 template type(模板型別)

與vector不同的是,initializer_list 中的元素值皆是const常值:

Unlike vector , the elements in an initializer_list are always const values; there

void error_msg(initializer_list<string> il)

{

for (auto beg = il.begin(); beg != il.end(); ++beg)

cout << *beg << " ";

cout << endl;

}

當我們傳入一序列的值給一個initializer_list參數,我們必須將該序列以大括號圍起: 第76集 7:12:40





void error_msg(ErrCode e, initializer_list<string> il)

{

cout << e.msg() << ": ";

for (const auto &elem : il)

cout << elem << " ";

cout << endl;

}

第76集 7:13:30



頁222

Ellipsis Parameters

Ellipsis參數之所以會出現在C++中,是為了讓程式能與用到C程式庫中varargs機能的C 程式碼互動。一般來說,ellipsis參數不應該用於其他目的。你C編譯器的說明文件會描述如何使用varargs。

WARNING:

Ellipsis參數應該只用於C與C++共通的型別之上。特別是,大多數類別型別的物件傳入給一個ellipsis參數時,都無法正確拷貝。

Ellipsis 參數 省略參數 第76集7:30:00

varargs

varying arguments

ellipsis參數只能出現在參數列的末後(殿後),可以有2種表達式:

void foo(parm_list, ...);

void foo(...);//真按:只有一個的話,它當就是最後一個了

2:8:00真的就是刪節號(即3個句號或小數點) 第65集 2:10:00 bind函式就用上這種參數 參見練習10.23



頁441

The Word Transformation Program

transformation在此(中文語境)應譯為「取代字串」或「文字轉換」第76集 1:0:10 參見Chapter 12. Dynamic Memory「文字查詢程式」



練習11.35

下標(subscript)者,會改動已有key的value值,而插入insert()者不會(即若鍵值已存在,則不會再插入!) 第76集 41:00 46:20

https://github.com/oscarsun72/prog1-C-Primer-5th-Edition-s-Exercises/blob/exercise11_35/prog1/prog1.cpp

留言

熱門文章