41、vector、list、deque的性能初窺
int large_size = 10000000;
cout_current_time("start init vector!\t");
vector<string> svec1(large_size, "Hello");
vector<string> svec2(large_size, "Hi");
cout_current_time("end init vector!\t");
cout_current_time("start init list!\t");
list<string> slist1(large_size, "Hello");
list<string> slist2(large_size, "Hi");
cout_current_time("end init list!\t");
cout_current_time("start init deque!\t");
deque<string> sdeq1(large_size, "Hello");
deque<string> sdeq2(large_size, "Hi");
cout_current_time("end init deque!\t");
用事實說話最有說服力:
start init vector! current time : 5:5:52
end init vector! current time : 5:5:55
start init list! current time : 5:5:55
end init list! current time : 5:6:14
start init deque! current time : 5:6:14
end init deque! current time : 5:6:26
可以看出大致時間比例為3/19/12。雖然不足以佐證它們的性能差距,但vector的常用似乎有了更充分的理由。
這里使用了一個簡單的時間函數大致如下:
#include <time.h>
typedef struct tm * time_type;
time_type get_current_time(void) {
time_t t;
t = time(NULL);
return localtime(&t);
}
42、容器自增長(P286)
每種實現都要求遵循以下原則:確保push_back操作高效地在vector中添加元素。從技術上來說,在原來為空的vector容器上n次調用push_back函數,從而創建擁有n個元素的vector容器,其執行時間永遠不能超過n的常量倍。
43、類定義中為何不能具有自身的數據成員(P375)
因為只有當類定義體完成后才能定義類,因此類不能具有自身類型的數據成員。然而,只要類名一出現就可以認為該類已聲明。因此,類的數據成員可以是指向自身類型的指針或引用:
class LinkScreen {
Screen window;
LinkScreen *next;
LinkScreen *prev;
};
44、兩種引用類類型的方法(P376)
Sales_item item1; //default initialized object of type Sales_item
class Sales_item item1; //equivalent definition of item1
兩種引用類類型的方法是等價的。第二種方法是從C繼承而來的,在C++中仍然有效。第一種更為簡練,由C++語言引入,使得類類型更容易使用。
45、為什么類的定義以分號結束(P376)
分號是必須的,因為在類定義之后可以接一個對象定義列表。定義必須以分號結束:
class Sales_item {/* … */};
class Sales_item {/* … */} accum, trans;
46、形參表和函數體處于類作用域中,函數返回類型不一定在類作用域中
在定義于類外部的成員函數中,形參表和成員函數體都出現在成員名之后。這些都是在類作用域中定義,所以可以不用限定而引用其他成員。因為形參表是在Screen類作用域內,所以不必知名我們想要的是Screen::index。
如果返回類型使用由類定義的類型,則必須使用完全限定名。
#include "stdafx.h"
#include <iostream>
class MyClass
{
public :
typedef int index_t;
index_t twice(index_t in);
};
MyClass::index_t MyClass ::twice(index_t in)
{
return in * 2;
}
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
MyClass obj;
MyClass::index_t x, y;
x = 10;
y = obj.twice(x);
cout<<"x = "<<x<<"; y = "<<y<<";"<<endl;
return 0;
}
47、構造函數初始化式(P387)
與任意的成員函數一樣,構造函數可以定義在類的內部或外部。構造函數初始化式只在構造函數的定義中而不是聲明中指定。
構造函數初始化列表難以理解的一個原因在于,省略初始化列表并在構造函數的函數體內對數據成員賦值是合法的。
在構造函數初始化列表中沒有顯式提及的每個成員,使用與初始化變量相同的規則來進行初始化。運行該類型的默認構造函數,來初始化類類型的數據成員。內置或復合類型的成員的初始值依賴于對象的作用域:在局部作用域中這些成員不被初始化,而在全局作用域中它們被初始化為0。
如果那個類沒有默認構造函數,則編譯器嘗試使用默認構造函數將會失敗。在這種情況下,為了初始化數據成員,必須提供初始化式。
對于這樣的成員,在構造函數函數體中對它們賦值不起作用。沒有默認構造函數的類類型成員,以及const或引用類型的成員,不管是哪種類型,都必須在構造函數初始化列表中進行初始化。
因為內置類型的成員不進行隱式初始化,所以對這些成員是進行初始化還是賦值似乎都無關緊要。除了兩個例外,對非類類型的數據成員進行賦值或使用初始化式在結果和性能上都是等價的。
48、成員初始化的次序
構造函數初始化列表僅指定用于初始化成員的值,并不指定這些初始化執行的次序。成員被初始化的次序就是定義成員的次序。
class X{
int i;
int j;
public:
//run-time error: i is initialized before j
X(int val): j(val), i(j) {}
}
在這種情況下,構造函數初始化列表看起來似乎是用val初始化j,然后再用j來初始化i。然而i首先被初始化。這個初始化列表的效果是用尚未初始化的j值來初始化i!
49、使用默認構造函數(P393)
常犯的一個錯誤是采用以下方式聲明一個用默認構造函數初始化的對象:
Sales_item myobj();
Sales_item myobj(); //ok: but defines a function, not an object
if(myobj.same_isbn(Primer_3rd_ed)) // error: myobj is a function
正確的方式應該是去掉相應的括號:
Sales_item myobj;
或者
Sales_item myobj = Sales_item();
50、顯式或隱式初始化
#include "stdafx.h"
#include <iostream>
using namespace std;
class MyClass
{
public :
typedef int index_t;
bool same_object(MyClass obj);
public :
MyClass(int default_index = 5)
:default_index(default_index),
m_name("default_name"){}
MyClass::MyClass(std::string name);
public :
int default_index;
std::string m_name;
};
MyClass::MyClass(std::string name)
:default_index(0), m_name(name){}
bool MyClass::same_object(MyClass obj)
{
cout<<"m_name = "<<m_name.c_str()<<endl;
cout<<"obj.m_name = "<<obj.m_name.c_str()<<endl;
return strcmp(obj.m_name.c_str(), m_name.c_str()) == 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
MyClass obj;
cout<<"explicit : "<<obj.same_object(MyClass("default_name"))<<endl;
cout<<"implicit : "<<obj.same_object(string("default_name"))<<endl;
return 0;
}
因為具有以std::string為形參的構造函數,因此在調用需要MyClass對象的same_object成員函數時,會自動隱式調用該構造函數構建MyClass對象,用于操作。但生成的MyClass對象是臨時對象,在same_object函數調用完成后銷毀。如果為了避免產生隱式轉換可以使用explicit關鍵字來抑制由構造函數定義的隱式轉換:
