青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

MyMSDN

MyMSDN記錄開發(fā)新知道

#

Expert C Programming notes

1、const其實(shí)并不是真正的常量(P32)

const_is_not_constant

2、早期的gets()中的Bug導(dǎo)致了Internet蠕蟲(P42)

gets()函數(shù)并不檢查緩沖區(qū)的空間,事實(shí)上它也無法檢查緩沖區(qū)的空間。如果函數(shù)的調(diào)用者提供了一個(gè)指向堆棧的指針,并且gets()函數(shù)讀入的字符數(shù)量超過緩沖區(qū)的空間,gets()函數(shù)將會(huì)愉快地將多出來的字符繼續(xù)寫入到堆棧中,這就覆蓋了堆棧原先的內(nèi)容。——這就是病毒利用它來寫入額外空間,并引發(fā)蠕蟲病毒的前提。

推薦的方式是將

gets(line)

替換為

if(fgets(line, sizeof(line), stdin) == NULL)

exit(1);

3、相鄰字符串常量自動(dòng)連接(P45)

這個(gè)其實(shí)已經(jīng)應(yīng)用很普遍了,但是我個(gè)人用的比較少,特此記錄一下。

ansi-c_connect_string

4、返回一個(gè)指針?(P48)

這個(gè)話題圍繞一個(gè)程序的BUG來展開,這個(gè)程序返回了局部變量的值的指針,這么說當(dāng)然你一眼就能看得出來問題所在,但是在很多時(shí)候,這個(gè)錯(cuò)誤卻總是在你的眼皮子底下溜走。

作者提供了五種方式,只能說可以用,但唯一推薦的只有一個(gè),詳見作者的分析(P48)(不是什么高深的理論,你自己也能分析地出來)。

a.返回一個(gè)字符串常量的指針。因?yàn)槌A看嬖陟o態(tài)數(shù)據(jù)存儲(chǔ)區(qū),所以指針沒問題。

b.使用全局聲明的數(shù)組。提到全局兩個(gè)字,就知道這個(gè)方法有很大的局限性。

c.使用靜態(tài)數(shù)組。下一次調(diào)用將覆蓋這個(gè)數(shù)組內(nèi)容。

char * func() {

static char buffer[20];

return buffer;

}

d.顯式分配一些內(nèi)存,保存返回的值。

char  * func() {

char * s = malloc(120);

return s;

}

既然用到了malloc,就必然伴隨著free,因此帶來了內(nèi)存管理的問題,增加了開發(fā)者負(fù)擔(dān)。

e.(推薦)在調(diào)用前后,由函數(shù)調(diào)用者分配內(nèi)存,并由其釋放,在同一地方釋放對(duì)于內(nèi)存管理來說代價(jià)相對(duì)最小。

void func( char * result, int size) {

strncpy(result, “That’d be in the data segment, Bob”, size);

}

buffer = malloc(size);

func(buffer, size);

free(buffer);

posted @ 2009-04-01 00:31 volnet 閱讀(337) | 評(píng)論 (0)編輯 收藏

QuickSort快速排序法(2009-03-06)

本文代碼已經(jīng)更新,修正嚴(yán)重BUG,最新版本詳見《QuickSort快速排序法(2009-10-28)》!

本文中所涉及的代碼未做更新,請(qǐng)移步最新版查閱正確代碼!

鏈接:http://m.shnenglu.com/mymsdn/archive/2009/10/28/quicksort20091028.html


快速排序法:(好土,感覺滿世界都會(huì),不過還是寫一下,當(dāng)然了,標(biāo)準(zhǔn)庫里多的是排序算法),這里還是實(shí)現(xiàn)經(jīng)典版的快速排序了,時(shí)間復(fù)雜度O(nlogn)

Algorithms.h

#pragma once

#include <iostream>

class Algorithms
{
public:
    Algorithms(void);
    ~Algorithms(void);

public:
    template <typename T>
    static void QuickSort(T* arr, size_t min, size_t max);
private:
    template <typename T>
    static size_t qsort_helper_partition(T* arr, size_t min, size_t max);
    template <typename T>
    static inline void swap(T* arr, size_t x, size_t y);
};

template <typename T>
void Algorithms::QuickSort(T* arr, size_t min, size_t max)
{
    if(min >= max || max == 0 - 1) return;
    size_t p = qsort_helper_partition(arr, min, max);

    QuickSort(arr, min, p - 1);
    QuickSort(arr, p + 1, max);
}

template <typename T>
size_t Algorithms::qsort_helper_partition(T* arr, size_t min, size_t max)
{
    T cmp = arr[min];
    int i = min + 1, j = max;
    while(true)
    {
        while(cmp < arr[i])
            ++i;
        while(arr[j] < cmp)
            --j;
        if(i >= j) break;

        swap(arr, i, j);
    }
    swap(arr, min, j);
    return j;
}

template <typename T>
void Algorithms::swap(T* arr, size_t x, size_t y)
{
    T tmp = arr[x];
    arr[x] = arr[y];
    arr[y] = tmp;
}

用法:(順便有標(biāo)準(zhǔn)庫的排序法,當(dāng)然只是調(diào)一下,沒有什么可說的了)

#include "Algorithms.h"
#include <iostream>
#include <vector>
#include <algorithm>

int _tmain(int argc, _TCHAR* argv[])
{
    int arr[] = {4, 8, 3, 7, 1, 5, 6, 2};

    for(size_t i = 0; i != 8; ++i)
    {
        std::cout<<arr[i]<<" ";
    }
    std::cout<<std::endl;

    Algorithms::QuickSort(arr,0, 7);

    for(size_t i = 0; i != 8; ++i)
    {
        std::cout<<arr[i]<<" ";
    }
    std::cout<<std::endl;

    std::vector<int> vec;
    vec.push_back(3);
    vec.push_back(1);
    vec.push_back(4);
    vec.push_back(1);
    vec.push_back(7);
    vec.push_back(6);

    for(std::vector<int>::iterator iter = vec.begin();
        iter != vec.end(); ++ iter)
    {
        std::cout<<*iter<<" ";
    }
    std::cout<<std::endl;

    std::sort(vec.begin(), vec.end());

    for(std::vector<int>::iterator iter = vec.begin();
        iter != vec.end(); ++ iter)
    {
        std::cout<<*iter<<" ";
    }
    std::cout<<std::endl;

    return 0;
}

posted @ 2009-03-06 03:03 volnet 閱讀(1223) | 評(píng)論 (5)編輯 收藏

最大公約數(shù)問題

image

image

image

image

image 

image

image

image

image

以上內(nèi)容摘自《編程之美》P150-154。

為了方便使用,下面是可拷貝的代碼:

Math.h

#pragma once

class Math
{
public:
    Math(void);
    ~Math(void);

public :
    //編程之美P150-154

    //求最大公約數(shù),歐幾里德——輾轉(zhuǎn)相除法
    static int Gcd1(int x, int y);

    //求最大公約數(shù),歐幾里德——輾轉(zhuǎn)相除法(變相將除法變成了減法)
    static int Gcd2(int x, int y);

    static int Gcd3(int x, int y);

    inline static bool IsEven(int x);

    inline static int Absolute(int x);
};

Math.cpp

#include "Math.h"

Math::Math(void)
{
}

Math::~Math(void)
{
}

int Math::Gcd1(int x, int y)
{
    //y, x%y順序不能錯(cuò);
    return y ? Gcd1(y, x % y) : x;
}

int Math::Gcd2(int x, int y)
{
    //與Gcd1相同的方式,但由于x%y計(jì)算速度較x-y要慢,但效果相同,所以換用x - y
    // 但用減法和除法不同的是,比如和,%20=10,-20=70,也就是-4×=10
    // 也就是說迭代次數(shù)較Gcd1而言通常是增加了。
    return y ? Gcd1(y, x - y) : x;
}

int Math::Gcd3(int x, int y)
{
    if(x < y)
        return Gcd3(y, x);
    if(y == 0)
        return x;
    else
    {
        if(IsEven(x))
        {
            if(IsEven(y))
                return (Gcd3(x >> 1, y >> 1) << 1);
            else
                return Gcd3(x >> 1, y);
        }
        else
        {
            if(IsEven(y))
                return Gcd3(x, y >> 1);
            else
                return Gcd3(y, x - y);
        }
    }
}

bool Math::IsEven(int x)
{
    return !(bool)x & 0x0001;
}

int Math::Absolute(int x)
{
    return x < 0 ? -x : x;
}

Main.cpp

#include <stdafx.h>
#include <iostream>
#include "Math.h"

using namespace std;
int _tmain(const int & arg)
{
    cout<<"Math::Gcd1(42,30) = "<<Math::Gcd1(42,30)<<endl;
    cout<<"Math::Gcd1(30,42) = "<<Math::Gcd1(30,42)<<endl;
    cout<<"Math::Gcd1(50,50) = "<<Math::Gcd1(50,50)<<endl;
    cout<<"Math::Gcd1(0,0) = "<<Math::Gcd1(0,0)<<endl;
    cout<<"Math::Gcd1(-42,-30) = "<<Math::Gcd1(-42,-30)<<endl;
    cout<<"Math::Gcd1(-42,30) = "<<Math::Gcd1(-42,30)<<endl;

    cout<<"------------------------------"<<endl;

    cout<<"Math::Gcd2(42,30) = "<<Math::Gcd2(42,30)<<endl;
    cout<<"Math::Gcd2(30,42) = "<<Math::Gcd2(30,42)<<endl;
    cout<<"Math::Gcd2(50,50) = "<<Math::Gcd2(50,50)<<endl;
    cout<<"Math::Gcd2(0,0) = "<<Math::Gcd2(0,0)<<endl;
    cout<<"Math::Gcd2(-42,-30) = "<<Math::Gcd2(-42,-30)<<endl;
    cout<<"Math::Gcd2(-42,30) = "<<Math::Gcd2(-42,30)<<endl;

    cout<<"------------------------------"<<endl;

    cout<<"Math::Gcd3(42,30) = "<<Math::Gcd3(42,30)<<endl;
    cout<<"Math::Gcd3(30,42) = "<<Math::Gcd3(30,42)<<endl;
    cout<<"Math::Gcd3(50,50) = "<<Math::Gcd3(50,50)<<endl;
    cout<<"Math::Gcd3(0,0) = "<<Math::Gcd3(0,0)<<endl;
    cout<<"Math::Gcd3(-42,-30) = "<<Math::Gcd3(-42,-30)<<endl;
    cout<<"Math::Gcd3(-42,30) = "<<Math::Gcd3(-42,30)<<endl;

    return 0;
}

不過有一點(diǎn)值得一提,就是所謂性能最好效率最高的Gcd3不支持負(fù)數(shù),也就是最后兩行測試代碼無法通過。但是限于對(duì)負(fù)數(shù)的最大公約數(shù)并沒有定義,也就是說即便上面的Gcd1和Gcd2好像算出了負(fù)數(shù),但它們的結(jié)果沒有意義。

posted @ 2009-03-04 23:52 volnet 閱讀(1048) | 評(píng)論 (0)編輯 收藏

a Swap program

#include "stdio.h"
#include "stdlib.h"

void foo(int *a, int *b) {
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
}
int main(void) {
    int a = 1, b = 2, c = 3;
    foo(&a, &b);
    foo(&b, &c);
    foo(&c, &a);
    printf("%d, %d, %d", a, b, c);
    return EXIT_SUCCESS;
}

foo看似繚亂卻是一個(gè)交換函數(shù):

從最后一次做*a和*b的位置開始向上:

也就是*b = *a - *b;擴(kuò)展為*b = (*a + *b) - *b展開就是*b = *a;也就是將*a的值賦給了*b。(注意到在此之前*b從未改變過)

*a = *a - *b(這時(shí)候不能用上一行的結(jié)論,因?yàn)?a曾經(jīng)改變過了)擴(kuò)展為*a = (*a + *b) – *a 也就是*a = *b,這里*b是指原始的*b,而不是上一行的結(jié)論,至此就交換完畢。

可以注意到,這里并沒有使用臨時(shí)變量。所以這是一個(gè)不需要臨時(shí)變量的交換方法。不過這種方法只支持支持operator+和operator-的數(shù)值計(jì)算(基本上只能用在整數(shù)上,因?yàn)閷?duì)浮點(diǎn)的操作可能涉及到舍入的問題)

而且這個(gè)方法還有一個(gè)缺陷,就是對(duì)數(shù)值邊界的判斷,比入MAX_INT+MAX_INT就溢出了,所以它存在一定的局限性。

posted @ 2009-02-24 18:29 volnet 閱讀(291) | 評(píng)論 (0)編輯 收藏

關(guān)于C++ Template分離頭文件和定義所產(chǎn)生的錯(cuò)誤

編譯錯(cuò)誤

如圖所示的代碼出現(xiàn)了如圖所示的錯(cuò)誤,誰能解釋一下是為什么呢?

雖然在最后include進(jìn)了cpp文件,而且這種做法也在C++ Primer中也是正確的(難道是標(biāo)準(zhǔn)和現(xiàn)實(shí)的差距?)。將代碼稍微變動(dòng),并將cpp部分的內(nèi)容移到.h文件中的include位置即可正確編譯。

編譯正確

posted @ 2009-02-22 06:05 volnet 閱讀(4356) | 評(píng)論 (20)編輯 收藏

將數(shù)組作為實(shí)參傳遞

在C++中我們應(yīng)該少用指針,多用引用,原因請(qǐng)大家自行搜索。在傳遞數(shù)組的時(shí)候我們需要格外注意,先讓我們看一個(gè)簡單的范例。

// PassArray.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//

#include "stdafx.h"
#include <iostream>

using namespace std;

template <typename T>
void Func1(T, T);
template <typename T>
void Func2(T&, T&);
void Func3(int (&)[10], int (&)[12]);

int _tmain(int argc, _TCHAR* argv[])
{
    int a[10], b[12];

    Func1(a, b);
    Func2(a, b);
    Func3(a, b);

    return 0;
}

template <typename T>
void Func1(T, T)
{
    cout<<"Func1.invoked!"<<endl;
}
template <typename T>
void Func2(T&, T&)
{
    cout<<"Func2.invoked!"<<endl;
}
void Func3(int (&m)[10], int (&n)[12])
{
    cout<<"Func3.invoked!"<<endl;
}

首先這個(gè)范例無法編譯通過:

error C2782

原因就出在類型推斷上。根據(jù)定義,F(xiàn)unc2的類型必須是T&,也就是說傳遞實(shí)參的時(shí)候,兩個(gè)形參必須是相同的,而這一點(diǎn)在模板編程中就會(huì)由編譯器來負(fù)責(zé)推斷。

Func1:

調(diào)用Func1(a, b)則推斷的類型分別是Func1(int*, int*),調(diào)用函數(shù)將會(huì)自動(dòng)將數(shù)組的首地址指針作為實(shí)參進(jìn)行傳遞,因此類型推斷兩形參相同,編譯通過!

Func2:

調(diào)用Func2(a, b)因?yàn)槲覀兿M匆玫姆绞竭M(jìn)行實(shí)參傳遞,因此需要遵循這樣的規(guī)律:

(P208)如果形參是數(shù)組的引用,編譯器將不會(huì)將數(shù)組實(shí)參轉(zhuǎn)化為指針,而是傳遞數(shù)組引用的本身。在這種情況下,數(shù)組大小成為形參和實(shí)參類型的一部分。

所以推斷類型分別是Func2(int (&)[10], int (&)[12]),因?yàn)閕nt (&)[10] != int (&)[12],所以與T == T相悖!自然也就編譯不過了!

Func3:

該函數(shù)是Func2的一個(gè)靜態(tài)表示,通過上面的解釋應(yīng)該很容易理解這個(gè)代碼了。

posted @ 2009-02-19 21:35 volnet 閱讀(1731) | 評(píng)論 (0)編輯 收藏

計(jì)時(shí)器代碼片段

這不是一個(gè)面向?qū)ο蟮拇a庫,它的存在僅僅只是為了說明幾個(gè)函數(shù)調(diào)用,如果要在您的工程中應(yīng)用相關(guān)內(nèi)容,請(qǐng)自行構(gòu)建(這應(yīng)該不難),或者看看我推薦的文檔。

// ProcessAffinity.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。
//

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <vector>

using namespace std;
void DisplayFrequency(ostream &out, LARGE_INTEGER &freq);

struct TimeSpan
{
    LARGE_INTEGER *Frequency;
    LARGE_INTEGER StartCounter;
    LARGE_INTEGER StopCounter;
    BOOL HAS_ERROR;
    double CalTimeSpan(){
        return (StopCounter.QuadPart - StartCounter.QuadPart)/Frequency->QuadPart;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE CurrentProcessHandle;
    DWORD ProcessAffinityMask, SystemAffinityMask, AllowProcessAffinity;

    CurrentProcessHandle = GetCurrentProcess();

    //GetCurrentProcess返回一個(gè)常量,代表當(dāng)前的進(jìn)程句柄
    cout<<CurrentProcessHandle<<endl;
    cout<<(HANDLE)-1<<endl;
    cout<<(void*)-1<<endl;
    cout<<(void*)0xffffffff<<endl;

    cout<<"-----------------------------"<<endl;

    if(GetProcessAffinityMask(CurrentProcessHandle, &ProcessAffinityMask, &SystemAffinityMask))
    {
        cout<<ProcessAffinityMask<<endl;    //0x0001
        cout<<SystemAffinityMask<<endl;        //0x0001
    
        AllowProcessAffinity = ProcessAffinityMask & SystemAffinityMask;
        cout<<AllowProcessAffinity<<endl;
    }

    LARGE_INTEGER Freq;
    typedef vector<LARGE_INTEGER> FreqVec_type;
    FreqVec_type FreqVec;
    
    while(FreqVec.size() != 5)
    {
        if(QueryPerformanceFrequency(&Freq))
        {
            DisplayFrequency(cout, Freq);
            FreqVec.push_back(Freq);
        }
        Sleep(1000);
    }

    for(FreqVec_type::iterator iter = FreqVec.begin(); iter!=FreqVec.end(); ++iter)
    {
        DisplayFrequency(cout, *iter);
    }

    cout<<"---------------------"<<endl;

    //calculate the timeSpan;
    TimeSpan ts;
    int sleepTime(3123);

    ts.Frequency = &Freq;

    if(QueryPerformanceCounter(&ts.StartCounter))
    {
        ts.HAS_ERROR = false;
        Sleep(sleepTime);
    }
    if(!ts.HAS_ERROR)
    {
        QueryPerformanceCounter(&ts.StopCounter);
    }
    
    cout<<ts.CalTimeSpan()<<endl;
    cout<<(ts.StopCounter.QuadPart-ts.StartCounter.QuadPart)/sleepTime<<endl;

    return 0;
}

void DisplayFrequency(ostream &out, LARGE_INTEGER &freq)
{
    out<<"start display!"<<endl;
    out<<freq.HighPart<<endl;
    out<<freq.LowPart<<endl;
    out<<freq.QuadPart<<endl;
    out<<"end display!"<<endl;
}

推薦文檔:《使用增強(qiáng)的計(jì)時(shí)器測量代碼段》(下載可適合打印,已排版,閱讀該文檔需要使用Microsoft Word 2007或相關(guān)閱讀器(后綴docx),如您需要pdf文檔,可以給我留言,我會(huì)將它發(fā)給你,在CSDN的下載中,您可能需要注冊(cè)成為相關(guān)網(wǎng)站的會(huì)員,或者使用積分,如果您覺得麻煩,可以直接向我索取!點(diǎn)此獲取!

posted @ 2009-02-19 01:49 volnet 閱讀(664) | 評(píng)論 (0)編輯 收藏

什么是句柄?為什么會(huì)有句柄?HANDLE

關(guān)鍵字:句柄, HANDLE, WINDOWS SDK, windows.h,

從廣義上,能夠從一個(gè)數(shù)值拎起一大堆數(shù)據(jù)的東西都可以叫做句柄。句柄的英文是"Handle",本義就是"柄",只是在計(jì)算機(jī)科學(xué)中,被特別地翻譯成"句柄",其實(shí)還是個(gè)"柄"。從一個(gè)小東西拎起一大堆東西,這難道不像是個(gè)"柄"嗎?

然后,指針其實(shí)也是一種"句柄",只是由于指針同時(shí)擁有更特殊的含義——實(shí)實(shí)在在地對(duì)應(yīng)內(nèi)存里地一個(gè)地址——所以,通常不把指針說成是"句柄"。但指針也有著能從一個(gè)32位的值引用到一大堆數(shù)據(jù)的作用,這不是句柄又是什么?

Windows系統(tǒng)中有許多內(nèi)核對(duì)象(這里的對(duì)象不完全等價(jià)于"面向?qū)ο蟪绦蛟O(shè)計(jì)"一詞中的"對(duì)象",雖然實(shí)質(zhì)上還真差不多),比如打開的文件,創(chuàng)建的線程,程序的窗口,等等。這些重要的對(duì)象肯定不是4個(gè)字節(jié)或者8個(gè)字節(jié)足以完全描述的,他們擁有大量的屬性。為了保存這樣一個(gè)"對(duì)象"的狀態(tài),往往需要上百甚至上千字節(jié)的內(nèi)存空間,那么怎么在程序間或程序內(nèi)部的子過程(函數(shù))之間傳遞這些數(shù)據(jù)呢?拖著這成百上千的字節(jié)拷貝來拷貝去嗎?顯然會(huì)浪費(fèi)效率。那么怎么辦?當(dāng)然傳遞這些對(duì)象的首地址是一個(gè)辦法,但這至少有兩個(gè)缺點(diǎn):

  1. 暴露了內(nèi)核對(duì)象本身,使得程序(而不是操作系統(tǒng)內(nèi)核)也可以任意地修改對(duì)象地內(nèi)部狀態(tài)(首地址都知道了,還有什么不能改的?),這顯然是操作系統(tǒng)內(nèi)核所不允許的;
  2. 操作系統(tǒng)有定期整理內(nèi)存的責(zé)任,如果一些內(nèi)存整理過一次后,對(duì)象被搬走了怎么辦?

所以,Windows操作系統(tǒng)就采用進(jìn)一步的間接:在進(jìn)程的地址空間中設(shè)一張表,表里頭專門保存一些編號(hào)和由這個(gè)編號(hào)對(duì)應(yīng)一個(gè)地址,而由那個(gè)地址去引用實(shí)際的對(duì)象,這個(gè)編號(hào)跟那個(gè)地址在數(shù)值上沒有任何規(guī)律性的聯(lián)系,純粹是個(gè)映射而已。

在Windows系統(tǒng)中,這個(gè)編號(hào)就叫做"句柄"。

?

Handle在Windows中的含義很廣泛,以下關(guān)于談到的Handle除非特別說明,將僅限于進(jìn)程、線程的上下文中。

1、先來談?wù)凥andle

Handle本身是一個(gè)32位的無符號(hào)整數(shù),它用來代表一個(gè)內(nèi)核對(duì)象。它并不指向?qū)嶋H的內(nèi)核對(duì)象,用戶模式下的程序永遠(yuǎn)不可能獲得一個(gè)內(nèi)核對(duì)象的實(shí)際地址(一般情況下)。那么Handle的意義何在?它實(shí)際上是作為一個(gè)索引在一個(gè)表中查找對(duì)應(yīng)的內(nèi)核對(duì)象的實(shí)際地址。那么這個(gè)表在哪里呢?每個(gè)進(jìn)程都有這樣的一個(gè)表,叫句柄表。該表的第一項(xiàng)就是進(jìn)程自己的句柄,這也是為什么你調(diào)用GetCurrentProcess()總是返回0x7FFFFFFF原因。

簡單地說,Handle就是一種用來"間接"代表一個(gè)內(nèi)核對(duì)象的整數(shù)值。你可以在程序中使用handle來代表你想要操作的內(nèi)核對(duì)象。這里的內(nèi)核對(duì)象包括:事件(Event)、線程、進(jìn)程、Mutex等等。我們最常見的就是文件句柄(file handle)。

另外要注意的是,Handle僅在其所屬的進(jìn)程中才有意義。將一個(gè)進(jìn)程擁有的handle傳給另一個(gè)進(jìn)程沒有任何意義,如果非要這么做,則需要使用DuplicateHandle(),在多個(gè)進(jìn)程間傳遞Handle是另外一個(gè)話題了,與這里要討論的無關(guān)。

2、進(jìn)程ID

首先,進(jìn)程ID是一個(gè)32位無符號(hào)整數(shù),每個(gè)進(jìn)程都有這樣的一個(gè)ID,并且該ID在系統(tǒng)范圍內(nèi)是唯一的。系統(tǒng)使用該ID來唯一確定一個(gè)進(jìn)程。

深入些說,系統(tǒng)可能使用進(jìn)程ID來計(jì)算代表該進(jìn)程的內(nèi)核對(duì)象的基地址(及EPROCESS結(jié)構(gòu)的基地址),具體的計(jì)算公式你可以去問微軟的OS開發(fā)人員。

3、HINSTANCE

HINSTANCE也是一個(gè)32無符號(hào)整數(shù),它表示程序加載到內(nèi)存中的基地址。

posted @ 2009-02-19 00:10 volnet 閱讀(25746) | 評(píng)論 (29)編輯 收藏

C++ notes (6)

51、static成員函數(shù)

因?yàn)閟tatic成員不是任何對(duì)象的組成部分,所以static成員函數(shù)不能被聲明為const。畢竟,將成員函數(shù)聲明為const就是承諾不會(huì)修改該函數(shù)所屬的對(duì)象。最后,static成員函數(shù)也不能被聲明為虛函數(shù)。

52、特殊的整型const static成員(P401)

const static數(shù)據(jù)成員在類的定義體中初始化時(shí),該數(shù)據(jù)成員仍必須在類的定義體之外進(jìn)行定義。

class Accout{

public:

static double rate() { return interestRate;}

static void rate(double); //sets a new rate

private:

static const int period = 30; //interest posted every 30 days

double daily_tbl[period]; // ok: period is constant expression

}

//definition of static member with no initializer;

//the initial value is specified inside the class definition

const int Accout::period;

但在gcc和MS vc++編譯器下似乎均不需要再次定義,也就是題設(shè)的“必須”二字在此失效。

53、操作符重載(P435)

下面是一些指導(dǎo)原則,有助于決定將操作符設(shè)置為類成員還是普通非成員函數(shù)

  • 賦值(=)、下標(biāo)([])、調(diào)用(())和成員訪問箭頭(->)等操作符必須定義為成員,將這些操作符定義為非成員函數(shù)將在編譯時(shí)標(biāo)記為錯(cuò)誤。
  • 像賦值一樣,復(fù)合賦值操作符通常應(yīng)定義為類的成員。與賦值不同的是,不一定非得這樣做,如果定義非成員復(fù)合賦值操作符,不會(huì)出現(xiàn)編譯錯(cuò)誤。
  • 改變對(duì)象狀態(tài)或與給定類型緊密聯(lián)系的其他一些操作符,如自增、自減和解引用,通常應(yīng)定義為類成員。
  • 對(duì)稱的操作符,如算術(shù)操作符、相等操作符、關(guān)系操作符和位操作符,最好定義為普通非成員函數(shù)。

54、區(qū)別操作符的前綴和后綴形式(P447)

同時(shí)定義前綴式操作符和后綴式操作符存在一個(gè)問題:它們的形參數(shù)目和類型相同,普通重載不能區(qū)別所定義的是前綴式操作符還是后綴式操作符。

為解決這一問題,后綴式操作符函數(shù)接受一個(gè)額外的(即,無用的)int型形參。使用后綴操作符時(shí),編譯器提供0作為這個(gè)形參的實(shí)參。盡管我們的前綴式操作符函數(shù)可以使用這個(gè)額外的形參,但通常不應(yīng)該這樣做。那個(gè)形參不是后綴式操作符的正常工作所需要的,它的唯一目的是使后綴函數(shù)與前綴函數(shù)區(qū)別開來。

55、顯式調(diào)用前綴式操作符

CheckedPtr parr(ia, ia+size); //ia points to an array of ints

parr.operator(0); //call postfix operator++

parr.operator(); //call prefix operator++

56、函數(shù)對(duì)象(P450)

struct absInt {

int operator() (int val){

       return val<0 ? –val : val;

}

};

int i = –42;

absInt absObj; //object that defines function call operator

unsigned int ui = absObj(i); //calls absInt::operator(int)

盡管absObj是一個(gè)對(duì)象而不是函數(shù),我們?nèi)匀豢梢?#8220;調(diào)用”該對(duì)象,效果是運(yùn)行由absObj對(duì)象定義的重載調(diào)用操作符,該操作符接受一個(gè)int值并返回它的絕對(duì)值。

函數(shù)對(duì)象經(jīng)常用作通用算法的實(shí)參。(詳見P450)

57、函數(shù)對(duì)象的函數(shù)適配器(P453)

標(biāo)準(zhǔn)庫提供了一組函數(shù)適配器(function adapter),用于特化和擴(kuò)展一元和二元函數(shù)對(duì)象。函數(shù)適配器分為如下兩類:

(1)綁定器(binder),是一種函數(shù)適配器,它通過將一個(gè)操作數(shù)綁定到給定值而將二元函數(shù)對(duì)象轉(zhuǎn)換為一元函數(shù)對(duì)象。(bind1stbind2nd 更多

(2)求反器(negator),是一種函數(shù)適配器,它將謂詞函數(shù)對(duì)象的真值求反。(not1not2 更多

58、轉(zhuǎn)換操作符(P455)

轉(zhuǎn)換為什么有用?(詳見P454)

轉(zhuǎn)換函數(shù)采用如下通用形式:

operator type();

這里,type表示內(nèi)置類型名、類類型名或由類型別名所定義的名字。對(duì)任何可作為函數(shù)返回類型的類型(除了void之外)都可以定義轉(zhuǎn)換函數(shù)。一般而言,不允許轉(zhuǎn)換為數(shù)組或函數(shù)類型,轉(zhuǎn)換為指針(數(shù)據(jù)或函數(shù)指針)以及引用類型是可以的。

轉(zhuǎn)換函數(shù)必須是成員函數(shù),不能指定返回類型,并且形參表必須為空。

轉(zhuǎn)換函數(shù)一般不應(yīng)該改變被轉(zhuǎn)換的對(duì)象。因此,轉(zhuǎn)換操作符通常應(yīng)定義為const成員。

59、只能應(yīng)用一個(gè)類類型轉(zhuǎn)換

類類型轉(zhuǎn)換之后不能再跟另一個(gè)類類型轉(zhuǎn)換。如果需要多個(gè)類類型轉(zhuǎn)換,則代碼將出錯(cuò)。

假設(shè)有Integral=>SmallInt=>int,但是如果有一個(gè)函數(shù)cal(int),那么對(duì)于SmallInt si,可以使用cal(si),但對(duì)于Integral intVal;則不能使用cal(intVal)。語言只允許一次類類型轉(zhuǎn)換,所以該調(diào)用出錯(cuò)。

60、virtual與其他成員函數(shù)(P479)

C++中的函數(shù)調(diào)用默認(rèn)不使用動(dòng)態(tài)綁定。要觸發(fā)動(dòng)態(tài)綁定,必須滿足兩個(gè)條件:第一,只有指定為虛函數(shù)的成員函數(shù)才能進(jìn)行動(dòng)態(tài)綁定,成員函數(shù)默認(rèn)為非虛函數(shù),非虛函數(shù)不進(jìn)行動(dòng)態(tài)綁定;第二,必須通過基類類型的引用或指針進(jìn)行函數(shù)調(diào)用。

基類類型引用和指針的關(guān)鍵點(diǎn)在于靜態(tài)類型(static type,在編譯時(shí)可知的引用類型或指針類型)和動(dòng)態(tài)類型(dynamic type,指針或引用所綁定的對(duì)象的類型,這是僅在運(yùn)行時(shí)可知的)可能不同。

posted @ 2009-02-15 02:28 volnet 閱讀(526) | 評(píng)論 (0)編輯 收藏

C++ notes (5)

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");

用事實(shí)說話最有說服力:

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

可以看出大致時(shí)間比例為3/19/12。雖然不足以佐證它們的性能差距,但vector的常用似乎有了更充分的理由。

這里使用了一個(gè)簡單的時(shí)間函數(shù)大致如下:

#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)

每種實(shí)現(xiàn)都要求遵循以下原則:確保push_back操作高效地在vector中添加元素。從技術(shù)上來說,在原來為空的vector容器上n次調(diào)用push_back函數(shù),從而創(chuàng)建擁有n個(gè)元素的vector容器,其執(zhí)行時(shí)間永遠(yuǎn)不能超過n的常量倍。

43、類定義中為何不能具有自身的數(shù)據(jù)成員(P375)

因?yàn)橹挥挟?dāng)類定義體完成后才能定義類,因此類不能具有自身類型的數(shù)據(jù)成員。然而,只要類名一出現(xiàn)就可以認(rèn)為該類已聲明。因此,類的數(shù)據(jù)成員可以是指向自身類型的指針或引用:

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

兩種引用類類型的方法是等價(jià)的。第二種方法是從C繼承而來的,在C++中仍然有效。第一種更為簡練,由C++語言引入,使得類類型更容易使用。

45、為什么類的定義以分號(hào)結(jié)束(P376)

分號(hào)是必須的,因?yàn)樵陬惗x之后可以接一個(gè)對(duì)象定義列表。定義必須以分號(hào)結(jié)束:

class Sales_item {/* … */};

class Sales_item {/* … */} accum, trans;

46、形參表和函數(shù)體處于類作用域中,函數(shù)返回類型不一定在類作用域中

在定義于類外部的成員函數(shù)中,形參表和成員函數(shù)體都出現(xiàn)在成員名之后。這些都是在類作用域中定義,所以可以不用限定而引用其他成員。因?yàn)樾螀⒈硎窃赟creen類作用域內(nèi),所以不必知名我們想要的是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、構(gòu)造函數(shù)初始化式(P387)

與任意的成員函數(shù)一樣,構(gòu)造函數(shù)可以定義在類的內(nèi)部或外部。構(gòu)造函數(shù)初始化式只在構(gòu)造函數(shù)的定義中而不是聲明中指定。

構(gòu)造函數(shù)初始化列表難以理解的一個(gè)原因在于,省略初始化列表并在構(gòu)造函數(shù)的函數(shù)體內(nèi)對(duì)數(shù)據(jù)成員賦值是合法的。

在構(gòu)造函數(shù)初始化列表中沒有顯式提及的每個(gè)成員,使用與初始化變量相同的規(guī)則來進(jìn)行初始化。運(yùn)行該類型的默認(rèn)構(gòu)造函數(shù),來初始化類類型的數(shù)據(jù)成員。內(nèi)置或復(fù)合類型的成員的初始值依賴于對(duì)象的作用域:在局部作用域中這些成員不被初始化,而在全局作用域中它們被初始化為0。

如果那個(gè)類沒有默認(rèn)構(gòu)造函數(shù),則編譯器嘗試使用默認(rèn)構(gòu)造函數(shù)將會(huì)失敗。在這種情況下,為了初始化數(shù)據(jù)成員,必須提供初始化式。

對(duì)于這樣的成員,在構(gòu)造函數(shù)函數(shù)體中對(duì)它們賦值不起作用。沒有默認(rèn)構(gòu)造函數(shù)的類類型成員,以及const或引用類型的成員,不管是哪種類型,都必須在構(gòu)造函數(shù)初始化列表中進(jìn)行初始化。

因?yàn)閮?nèi)置類型的成員不進(jìn)行隱式初始化,所以對(duì)這些成員是進(jìn)行初始化還是賦值似乎都無關(guān)緊要。除了兩個(gè)例外,對(duì)非類類型的數(shù)據(jù)成員進(jìn)行賦值或使用初始化式在結(jié)果和性能上都是等價(jià)的。

48、成員初始化的次序

構(gòu)造函數(shù)初始化列表僅指定用于初始化成員的值,并不指定這些初始化執(zhí)行的次序。成員被初始化的次序就是定義成員的次序。

class X{

int i;

int j;

public:

//run-time error: i is initialized before j

X(int val): j(val), i(j) {}

}

在這種情況下,構(gòu)造函數(shù)初始化列表看起來似乎是用val初始化j,然后再用j來初始化i。然而i首先被初始化。這個(gè)初始化列表的效果是用尚未初始化的j值來初始化i!

49、使用默認(rèn)構(gòu)造函數(shù)(P393)

常犯的一個(gè)錯(cuò)誤是采用以下方式聲明一個(gè)用默認(rèn)構(gòu)造函數(shù)初始化的對(duì)象:

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

正確的方式應(yīng)該是去掉相應(yīng)的括號(hào):

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;
}

因?yàn)榫哂幸詓td::string為形參的構(gòu)造函數(shù),因此在調(diào)用需要MyClass對(duì)象的same_object成員函數(shù)時(shí),會(huì)自動(dòng)隱式調(diào)用該構(gòu)造函數(shù)構(gòu)建MyClass對(duì)象,用于操作。但生成的MyClass對(duì)象是臨時(shí)對(duì)象,在same_object函數(shù)調(diào)用完成后銷毀。如果為了避免產(chǎn)生隱式轉(zhuǎn)換可以使用explicit關(guān)鍵字來抑制由構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換:

explicit

posted @ 2009-02-12 01:06 volnet 閱讀(1247) | 評(píng)論 (0)編輯 收藏

僅列出標(biāo)題
共9頁: 1 2 3 4 5 6 7 8 9 
特殊功能
 
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美精品 国产精品| 黄色成人在线网址| 国产日韩欧美高清| 一区二区三区免费观看| 欧美国产先锋| 久久精品国产999大香线蕉| 国产精品久久久久久久久动漫| 亚洲国产一成人久久精品| 久久精品日韩| 亚洲欧美资源在线| 国产性天天综合网| 久久精品男女| 欧美一区日韩一区| 国产亚洲免费的视频看| 亚洲欧美综合网| 亚洲无吗在线| 国产麻豆精品theporn| 欧美一级免费视频| 欧美一级片一区| 极品少妇一区二区三区| 久久尤物视频| 久久福利电影| 亚洲国产精品成人久久综合一区| 男人的天堂亚洲| 欧美极品影院| 午夜一区二区三区在线观看 | 老牛嫩草一区二区三区日本| 尤物在线精品| 欧美激情一区二区三区在线视频观看| 老司机免费视频一区二区| 在线欧美不卡| 亚洲国产精品电影在线观看| 欧美人与性动交cc0o| 亚洲综合欧美| 欧美在线网址| 亚洲美女精品成人在线视频| 一个人看的www久久| 国产农村妇女精品一二区| 欧美在线免费观看视频| 久久精品一本| 亚洲午夜小视频| 午夜国产精品视频| 亚洲国产日韩欧美一区二区三区| 亚洲国产视频a| 亚洲精品日韩在线| 一区二区三区日韩欧美| 国产精品视频导航| 久久久亚洲精品一区二区三区 | 韩国成人精品a∨在线观看| 老司机久久99久久精品播放免费| 欧美+亚洲+精品+三区| 亚洲色图制服丝袜| 亚洲女人av| 日韩香蕉视频| 久久电影一区| 亚洲欧美国产日韩天堂区| 久久精品国产91精品亚洲| 日韩视频一区二区三区在线播放免费观看 | 国产午夜亚洲精品羞羞网站| 亚洲高清不卡av| 国产精品系列在线| 亚洲国内精品| 在线观看精品一区| 亚洲欧洲av一区二区| 亚洲最新在线| 久久亚洲色图| 久久久国产视频91| 国产精品久久久999| 亚洲成人在线视频播放 | 欧美一区二区三区免费看 | 国产精品私拍pans大尺度在线 | 欧美大片在线看免费观看| 久久国产精品第一页| 欧美激情综合| 欧美激情视频一区二区三区免费| 国产亚洲午夜| 亚洲欧美另类久久久精品2019| 一区二区成人精品| 欧美黑人多人双交| 欧美顶级少妇做爰| 尤物yw午夜国产精品视频明星| 亚洲欧美一区二区在线观看| 亚洲午夜在线观看| 欧美精品一区二区视频| 亚洲国产高潮在线观看| 韩国亚洲精品| 久久国产精品久久久久久| 久久国产成人| 国产亚洲一区在线| 欧美一区二区观看视频| 性欧美大战久久久久久久久| 欧美日韩另类国产亚洲欧美一级| 亚洲国产另类精品专区| 亚洲人成网站色ww在线| 免费久久99精品国产自在现线| 一本久道久久综合狠狠爱| 一区二区黄色| 欧美日韩中字| 99伊人成综合| 亚洲欧美日韩一区在线观看| 国产精品久久二区| 午夜精品久久久久| 久久国产精品黑丝| 国模大胆一区二区三区| 久久久91精品国产一区二区三区 | 亚洲一区二区毛片| 欧美中文字幕| 黄色影院成人| 免费成人在线观看视频| 亚洲精品国产精品国自产观看| 亚洲精选成人| 欧美视频专区一二在线观看| 亚洲香蕉成视频在线观看| 欧美一区中文字幕| 在线欧美日韩国产| 欧美精品三区| 亚洲欧美精品suv| 欧美成人69| 亚洲视频国产视频| 国产欧美日韩视频一区二区| 久久精品国产一区二区电影| 亚洲电影有码| 午夜亚洲福利| 亚洲福利视频一区二区| 欧美日韩精品系列| 久久国内精品视频| 亚洲精品在线电影| 久久露脸国产精品| 亚洲美女黄色片| 国产日韩1区| 欧美黄色精品| 午夜精品电影| 亚洲经典在线看| 久久国产精品久久精品国产| 在线日韩视频| 国产精品久久久久9999吃药| 久久综合伊人| 欧美亚洲午夜视频在线观看| 亚洲国产精品一区制服丝袜| 久久av资源网站| 99视频在线精品国自产拍免费观看| 国产精品免费小视频| 麻豆亚洲精品| 欧美一区亚洲二区| 一本色道久久综合亚洲精品高清| 麻豆精品传媒视频| 新67194成人永久网站| 亚洲精品影视| 亚洲成在线观看| 国产一区香蕉久久| 国产精品扒开腿做爽爽爽视频| 玖玖精品视频| 久久精品麻豆| 亚洲欧美日韩成人| 一区二区三区精品在线| 最近看过的日韩成人| 久久永久免费| 久久久久国产精品人| 午夜一区二区三区在线观看| 一区二区三区精密机械公司 | 好看的亚洲午夜视频在线| 欧美午夜a级限制福利片| 欧美极品在线观看| 欧美大片一区二区三区| 久久狠狠一本精品综合网| 欧美日韩在线另类| 你懂的网址国产 欧美| 久久精品视频免费| 午夜日韩激情| 亚洲欧美日韩国产精品| 亚洲伦理在线免费看| 亚洲黄色成人| 亚洲激情二区| 亚洲黄色在线| 亚洲日本电影在线| 亚洲欧洲精品成人久久奇米网| 欧美成人免费在线| 欧美大片91| 亚洲电影成人| 欧美激情一区| 亚洲免费av网站| 99国产一区| 日韩香蕉视频| 一区二区三区免费看| 亚洲一区自拍| 欧美一区二区三区免费大片| 午夜精品福利视频| 久久av红桃一区二区小说| 久久久久久伊人| 毛片av中文字幕一区二区| 欧美成人一区二免费视频软件| 欧美激情第二页| 欧美午夜一区二区福利视频| 国产精品久久久久婷婷| 国产欧美日韩伦理| 国产综合亚洲精品一区二| 亚洲第一在线综合网站| 亚洲区中文字幕| 亚洲综合日韩| 美国十次成人|