点滴记录。
//事務處理不管如何,必定要獲得事務是否正確的標志,還要根據標志執行或回滾。
// 1.如sqllite這里到最后設置成功標志,并且無論如何會執行db.endTransaction();來進行判斷,執行還是回滾。
//2.還有mysql ,最后幾條語句直接根據系統的錯誤標志來進行判斷執行還是回滾。
進程和線程
所有的一切的根源是cpu太快。其他慢資源,如顯卡,聲卡等,更別說人類的操作,顯得是蝸牛的速度, 所以讓人類同時發出命令。 如阻塞了聲卡,那么讓不需要聲卡的進程用下cpu跑下。
所以劃分內存,劃分現場。來執行不同的程序。讓人看起來是同時執行。這就是進程。分配了內存和cpu,這就是所謂進程是資源分配的最小單位
而cpu還是太快,進程有時候會阻塞(等待網絡或其他資源),就算有多個,但是cpu實在太快。很多進程同時執行,在cpu看來,還有很多時間是在空轉。
而可以配合cpu把資源利用起來的有一個是內存。 內存一般不會用滿。所以cpu+內存。這個組合可以把cpu有效的利用起來,
所以進程可以開多個線程,尤其是單核時代,在等 IO 的時候,一般會手動開一個線程。利用cpu和內存來計算。
而到了多核時代,開線程就非常必要了。從硬件上面cpu直接開掛了。同時運行。
所以線程是CPU調度的最小單位,在進程中隨便開幾個線程是沒有問題的。
開線程后你把程序還理解為在一個線程在運行也是可以的。只要注意把內存保護好就可以。線程間沒有任何內存隔離保護的。
所以如果要安全的話:
共享數據建議必須都用類封裝。提供方法。可以清晰在多線程環境下進行。可以考慮定義一個接口類,所有進程的參數必須實現這個接口。就可以了。哈哈。而且進一步定義一個線程的接口類ithread。規定參數。
程序中必須使用 實現了ithread的線程。
可以隱喻為一個厲害的導演同時導演幾部不同風格的電影。而且導演在拍一個電影的同時,變拍戲邊炒菜。邊說這個演員往里走走,邊給爐子加火。 只要注意炒菜別用到劇組資源,否則加個鎖,讓劇組和導演線性使用爐子。
不同風格的電影就是不同的進程,吵菜等就是線程,炒菜不利用劇組緊張資源。
for 用于循環次數不變,而且最好從0開始,任何時候都表示次數,和邏輯不掛鉤。需要反序的話,自己用大數減i,
次數變化的用while處理。邏輯更簡潔。i就表示具體的業務數值了。
//recursion 和 循環的區別,除了性能和簡潔之外。
//recursion 還可以有一個回退上層的動作。如果需要回退上層再做一點事情,特別是必須從底往上的工作。那么recursion是非常合適的。聯想到平衡樹的插入之后檢查平衡的操作。
//如果不需要回退做任何工作。也就是尾遞歸。那么就用循環。
關于尾遞歸的詳細介紹:
https://baike.sogou.com/v162175.htm?fromTitle=%E5%B0%BE%E9%80%92%E5%BD%92
要滿足
1.遞歸在最后的語句,并且無任何動作。
2.即回歸無動作,因為循環是前進的,無法回撤到中途某現場。
具體可以看鏈接的例子。來思考1*2*3*4*5 的一般遞歸寫法和尾遞歸寫法。一般寫法是到最后一層才開始計算。而尾遞歸是中途就開始計算。到最后一層計算完畢。直接返回,重點,直接返回最終結果了。
return MyArrayList.this.theData[Index++];
是一個很好的后++的例子。next 需要返回某個item后,自動移動當前索引哨兵。 也說明了沒有太多東西是必要的。但是掌握后,可以簡潔有效。
//基于棧的特點和堆的特點,決定了,在函數內部是否需要new.
//清棧是函數離開自動清,所以盡量用棧.但是共享數據必須new,如給多個類使用(一般共享指針).
//棧大小默認都不大.小于1m.因此,大數據,如稍大的數組,必須new(一般共享指針).
//編譯器要求入棧必須確定棧的大小.可變的數組也必須new(一般用vector,數據是堆中的)
//由以上幾點,可推導出特殊需求,如共享一個可變數據.那么就是vector的共享指針.
//同理在類內部,由于不能確定類對象是否會被new,還是在棧中.也要避免棧的缺點.
//共享數據必須在外部new,類只需要包含指針。
//稍大的數組,必須new,析構函數delete
//可變的數組也必須new(一般用vector,數據是堆中的)
//如果是類內部new,那么必須析構delete
//一些外部api,一般需要的是指針,是堆指針還是棧指針,還是依據上面原則。
//有一些特殊,如這個api,是一個異步的處理。異步的回調,又傳出了這個指針,那么必須是new,要是堆中的。
1,windows下 ,c++ ,
,其實還是會插入
2.
因為系統提供的默認拷貝構造函數工作方式是內存拷貝,也就是淺拷貝。如果對象中用到了需要手動釋放的對象,則會出現問題,這時就要手動重載拷貝構造函數,實現深拷貝。
下面說說深拷貝與淺拷貝:
淺拷貝:如果復制的對象中引用了一個外部內容(例如分配在堆上的數據),那么在復制這個對象的時候,讓新舊兩個對象指向同一個外部內容,就是淺拷貝。(指針雖然復制了,但所指向的空間內容并沒有復制,而是由兩個對象共用).
2.int out 的參照物的內存。所以out 是從內存寫入到輸出設備。 in是從外部讀入到內存。
int main()
{
sales lulu=sales();
sales fun();// 從語法上看是定義了一個名為fun,返回值為sales的無參數函數。
sales lulu2=fun();
sales lulu3;
cout<<lulu.GetSalary()<<endl;
cout<<lulu2.GetSalary()<<endl;
cout<<lulu3.GetSalary()<<endl;
//lulu.Getjob(1000,3000);
return 0;
}
sales fun()
{
sales a;
return a;
}
聲明為explicit的構造函數不能在隱式轉換中使用
對比一下blockcode 和手工編譯的命名就可以知道以后怎么處理了。
構造函數的,初始化的參數是輸入構造參數的,不是說里面生成一個對象,在復制過去。
//多線程。
1)共享數據建議必須都用類封裝。提供方法。可以清晰在多線程環境下進行。
3)
socket 是雙向通訊
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
using namespace std;
int main()
{
int status;
int socketNo[2];
status=socketpair(AF_LOCAL,SOCK_STREAM,0,socketNo);
if(status==-1)
{
//printf("error:%s",strerror(errno));
printf("hihi");
}
else
{
cout<<socketNo[0]<<socketNo[1]<<endl;
}
status=write(socketNo[1],"hi",2);
if(status==0)
{
cout<<"error wirte"<<endl;
}
else
{
cout<<status<<endl;
}
char readStr[10];
status= read(socketNo[0],readStr,10);
if(status==0)
{
cout<<"error wirte"<<endl;
}
else
{
readStr[9]=0x0;
cout<<readStr<<endl;
}
status=write(socketNo[0],"hi, tow",10);
if(status==0)
{
cout<<"error wirte"<<endl;
}
else
{
cout<<status<<endl;
}
status= read(socketNo[1],readStr,10);
if(status==0)
{
cout<<"error wirte"<<endl;
}
else
{
readStr[9]=0x0;
cout<<readStr<<endl;
}
status= read(socketNo[1],readStr,10);
if(status==0)
{
cout<<"error wirte"<<endl;
}
else
{
readStr[9]=0x0;
cout<<readStr<<endl;
}
close(socketNo[0]);
close(socketNo[1]);
}
利用socket編程。如果使用tcp/ip協議棧,不需要考慮數據丟失,重復,順序,和溢出。onreceive 原則上是接受完了一個發送,才會給系統的。所以丟包不是上層程序會接觸到的。
幾本好書, 匯編原理, unix網絡編程.effect c++.簡明,詳細又深入.
1)socket下(短連接)一般編寫思路順序。
1.對象成員數據和方法。 涉及的收發消息格式。send并shutdown.
2.后臺線程的方法,涉及的收發消息格式。send并shutdown.
3.非阻塞下io的接收,涉及的收消息格式。receive 并function .
2)socket 下排錯。
1.先檢查客戶和服務端的內存數據。
2)再查看socket的收發狀態。
要這樣
vector<Book> mybooks=bookManager.GetmyBooks();
vector<Book>::iterator ret= MyFind(mybooks.begin(),mybooks.end());
千萬不能.
vector<Book>::iterator ret= MyFind(bookManager.GetmyBooks().begin(),bookManager.GetmyBooks().end());
mysql
PK:primary key 主鍵
NN:not null 非空
UQ:unique 唯一索引
BIN:binary 二進制數據(比text更大)
UN:unsigned 無符號(非負數)
ZF:zero fill 填充0 例如字段內容是1 int(4), 則內容顯示為0001
AI:auto increment 自增
g:所謂Cenerated Column,就是數據庫中這一列由其他列計算而得
MySQL 數據類型中的 integer types 有點奇怪。你可能會見到諸如:int(3)、int(4)、int(8) 之類的 int 數據類型。剛接觸 MySQL 的時候,我還以為 int(3) 占用的存儲空間比 int(4) 要小, int(4) 占用的存儲空間比 int(8) 小。
后來,參看 MySQL 手冊,發現自己理解錯了。
| 代碼如下 | 復制代碼 |
|
int(M): M indicates the maximum display width for integer types. |
|
在 integer 數據類型中,M 表示最大顯示寬度。
原來,在 int(M) 中,M 的值跟 int(M) 所占多少存儲空間并無任何關系。 int(3)、int(4)、int(8) 在磁盤上都是占用
4 btyes 的存儲空間。說白了,除了顯示給用戶的方式有點不同外,int(M) 跟 int 數據類型是相同的。
另外,int(M) 只有跟 zerofill 結合起來,才能使我們清楚的看到不同之處。
| 代碼如下 | 復制代碼 |
|
mysql> drop table if exists t; mysql> select * from t; mysql> alter table t change column id id int(3) zerofill; mysql> select * from t; mysql> mysql> select * from t; mysql> mysql> select * from t; |
|
從上面的測試可以看出,“(M)”指定了 int 型數值顯示的寬度,如果字段數據類型是 int(4),則:當顯示數值 10 時,在左邊要補上
“00”;當顯示數值 100 是,在左邊要補上“0”;當顯示數值 1000000 時,已經超過了指定寬度“(4)”,因此按原樣輸出。
在使用 MySQL 數據類型中的整數類型(tinyint、smallint、 mediumint、 int/integer、bigint)時,非特殊需求下,在數據類型后加個“(M)”,我想不出有何意義。
下面補充一下數據類型
1、整型
| MySQL數據類型 | 含義(有符號) |
| tinyint(m) | 1個字節 范圍(-128~127) |
| smallint(m) | 2個字節 范圍(-32768~32767) |
| mediumint(m) | 3個字節 范圍(-8388608~8388607) |
| int(m) | 4個字節 范圍(-2147483648~2147483647) |
| bigint(m) | 8個字節 范圍(+-9.22*10的18次方) |
取值范圍如果加了unsigned,則最大值翻倍,如tinyint unsigned的取值范圍為(0~256)。
int(m)里的m是表示SELECT查詢結果集中的顯示寬度,并不影響實際的取值范圍,沒有影響到顯示的寬度,不知道這個m有什么用。
2、浮點型(float和double)
| MySQL數據類型 | 含義 |
| float(m,d) | 單精度浮點型 8位精度(4字節) m總個數,d小數位 |
| double(m,d) | 雙精度浮點型 16位精度(8字節) m總個數,d小數位 |
設一個字段定義為float(5,3),如果插入一個數123.45678,實際數據庫里存的是123.457,但總個數還以實際為準,即6位。
3、定點數
浮點型在數據庫中存放的是近似值,而定點類型在數據庫中存放的是精確值。
decimal(m,d) 參數m<65 是總個數,d<30且 d<m 是小數位。
4、字符串(char,varchar,_text)
| MySQL數據類型 | 含義 |
| char(n) | 固定長度,最多255個字符 |
| varchar(n) | 固定長度,最多65535個字符 |
| tinytext | 可變長度,最多255個字符 |
| text | 可變長度,最多65535個字符 |
| mediumtext | 可變長度,最多2的24次方-1個字符 |
| longtext | 可變長度,最多2的32次方-1個字符 |
5.一個大坑。
使用類庫,類庫盡量不要存在靜態變量。非要使用,靜態變量的定義在類庫項目中。
盡量在大思路,大框架基本無盲點后開始項目開發。
選擇方案時,盡量模擬2個方法的得失,最關鍵是必須驗證可行。有時候冗余的方案,對于邏輯上反而更簡潔。
如果時間緊迫,也必須在開發模塊時,
1)把模塊的輸入,輸出壓縮到最小,
2)復雜的需求,分開做出幾個模塊,不要做大而全的模塊。特別是在需求會變或全新的項目下。
保證項目過程中的思路,框架的變更后,原有模塊可以完美適用。
不然,修改模塊是一個很耗費時間和測試的工作。切記!!!!!!!!!!!!!!!!!!!!!!!!!!!
寫模塊時,先從主輸入輸出模塊寫起。回調或委托先寫好,這樣,功能鋪開時,才好處理。各功能間的接口,參數就好確定。
目的:有時候有些情況比較復雜,寫完了代碼。也沒法確定是否完全正確。畫圖感覺比較復雜,只能靠測試。這個時候使用狀態機分析法。就能比較好。
所以最佳實踐:對象的創建,必須明確,僅僅是局部使用,還是會傳出去,局部使用,就可以直接在棧中,如果會傳出去(或返回,或包含在返回對象中),必須傳遞對象,或者堆中的地址(智能指針)
修改一些bug,或添加新功能時候,非常有必要一個一個來完整的修改測試。不然,一遍一遍的檢查是否完成, 修改完一個更新一個。難得可以先跳過。但不要做到一半!!!!!!!!!,切記。
不管是模塊設計,還是類規劃,還是小功能策劃,必須畫圖。就算是幾個方法的結合也必須畫圖。畫圖可以讓思路請i下。切記。queryreport的教訓。
按常理,一般半個工作日 可以整理 2天左右的代碼,大概10個左右方法。所以20!30個方法間的代碼,需要3天左右。別太盲目在緊急時重夠代碼。又是血的教育。一定要做好單元測試。這樣才是bug的保障。
內存對齊:
3規則
:第一個從0開始。
二:每個從自身的整數倍開始。
三,最后收尾按最大的類型的整數倍。
所以感覺隨意一點就只要先寫最小的。大的放最后,非要完全節省,就要細細擺了。感覺這個是編譯器的事情。不用太關注。
classS
{
inti;//0.3 第一規則
shorts[5];//4.13
charc;//14 補 到4的倍數, 14-15第三規則
};
classD
{
charc0;//0-0
doubled[3];//8-31第二規則
charc;//32 補 到8的倍數, 32-39第三規則
};
文件的操作。
常用就3種模式
附加:fstream fs(filepath.c_str(),ios_base::app|ios_base::out);
覆蓋:fstream fs(filepath.c_str(),ios_base::out);
讀起: ifstream fin;fin.open(filepath.c_str(),ios::in);
二維數組
int rows=5;
int column=6;
int **array3=new int*[rows];
for(int i=0;i<rows;++i)
{
array3[i]=new int[column];
}
array3[2][3]=5;
for(int i=0;i<rows;++i)
{
delete[] array3[i];
}
delete[] array3;
int* array2=new int[rows*column];
array2[0]=1;
array2[0+1]=2;
array2[1+0]=2;
for(int i=0;i<rows;++i)
{
for(int j=0;j<column;++j)
{
cout<<i*column+j;
array2[i*column+j]=i*10+j;
}
cout<<endl;
}
for(int i=0;i<30;++i)
{
cout<<array2[i]<<endl;
}
delete[] array2;
位運算符作用于位,并逐位執行操作。&、 | 和 ^
& 同時為真
| 有一個為真 : 更改某位值為1
2個不同且有一個為真。 :更改某位值為0
注意到一個使用指針的指針的場景。
系統或基礎類會生成一個指針,并且自己要使用到它。而使用者需要這個指針,那么可以設置一個出參,為指針的指針,來獲取。這樣就比較安全,簡便。
1。千萬不要返回局部對象的引用
2.在類的成員函數中,賦值可以返回*this.因為賦值是a=b。a是左值,是一定存在且this是隱指針參。
3.如ostream& operator<<(ostream& os,const compleNumber& complexNumb), 可以返回 os。
因為 cout<<b. cout是操作符左值,是一定存在的 且os是引用參數。
4。char& Mystring::operator[](unsigned int index)
這里也是一樣。this是隱指針參。
綜合所述,返回引用,一般是返回一個 引用參數,或指針參數 的全部或部分,或者局部靜態變量。
本質就是要求返回的對象,離開函數后是否還存在。存在才可以用引用。
1.
依賴倒置的理解:
按照直覺,是先寫個具體方法,再在上層調用這個方法。
而依賴倒置就是先寫上層方法。而具體方法可以先不寫,直接先用個抽象代替。
這個和事件驅動編程,就是一樣思維啊。
大部分的模式都是用了抽象的思想。抽象才是根本。
2.winform 第一個類不是頁面類,會打不開設計器。
移動第一個 非頁面類到后面。 是否ok了。否則 把輸入的下拉。從編譯改外無,再改為編譯,看看是否會重新加載設計器。
public FPSProcess()
{
preTime = System.DateTime.Now;
}
public DateTime preTime = System.DateTime.Parse("1982-01-02");
可以發現c#中,定義式居然比構造函數還早執行。這個。。。。
可以理解為c# ,一旦確定某個內存是什么數據,之后馬上在內存中放置默認值, 之后再執行 定義式和 構造函數。
所以會浪費幾條指令,但是保證了數據的類型正確。
所以最ok的做法還是任何類都定義默認的構造函數。而不放在定義式中。
后面發現和java是一樣的。構造函數會覆蓋定義。
4)第四個是模板,初寫模板,以為只是一套代碼的抽象。非常粗淺的看了c++的iterotarstl代碼,自己感覺原來模板才是真正的面向對象編程。之前真的只是面向類編程而已。繼續看下去。看下模板元編程會不會也有思維重大改變。
目前只有一個認識:無需繼承也可實現多態。模板是要錢出錢,要力出力,一聲令下,提前準備。所以模板會導致代碼膨脹。
新的認識:又一次被模板所驚嘆,既然是代碼生成器,那么對于可調用類型。如方法,防函數等 T(a),模板是不在乎T的類型的,所以一個模板類,可以同時接受函數對象和函數或函數指針。來完成一些可擴展的功能。如泛型算法,就可以接受任何可調用類型。
5)第五個是學習了c++后,再次復習c#,和java后的理解。更工業化的語言類的對象,都已經固定放在 heap中,讓人省去實例化后到底放哪里的考慮,一個簡單的強制設定,省去了無數的麻煩,自己學c++時,也曾打算這樣,和個人想法不謀而合,
完全可以避免棧滿的情況,看到類中的非基本數據成員,就知道是指針。而非基本數據成員,它其中的任何非基本數據成員,又一定是指針,非常清晰明白。感覺c#應該也是這樣設定的。所有對象都是new出來到堆中。
如果c++自由真的是完美的話,為什么所有公司都要裁剪呢?自由和強制都要把握度。
總結
- 上一篇: 使用openssl生成双向加密证书(转)
- 下一篇: 如何判别是光猫问题还是路由器的问题如何判