2013-09-27 154 views
4

我有一大塊代碼,它被設計用來獲取一個數組並通過它工作。在當前的項目中,只有一個元素,所以不是將變量更改爲char,而是將其聲明爲char數組[1]。這樣我就不需要修改我的代碼並可能會添加任何錯誤,並且可以在需求增長時輕鬆地增加它。array [1]發生了什麼

它似乎編譯好,但我已經變得好奇引擎蓋下發生了什麼,我浪費內存?這是否會增加額外的處理時間,編譯器是否會優化它,所以如果我輸入它就沒有什麼不同了?

任何人都可以解釋使用數組的任何可能的缺點就是這樣。

我用c和C++,它們之間會有什麼不同嗎?

回答

3

首先,你的代碼是有效的,但如果你關心的缺點,我可以看到下面列出的問題:

使用陣列,可以增加與外的界限訪問時,訪問它的機會您無需小心即可循環訪問數組。另一個缺點是數組不與多態相互作用。有時你嘗試將派生的對象存儲到一個基本類型的數組中,對象將被切片並且您可能不會注意到。

所以我不會寫數組[1]的代碼。希望這可以回答你的一些問題。

+0

'+ 1'表示可能出現循環錯誤。我希望特別在C. –

+4

好點,但由於OP說基於數組的代碼已經存在,所以我認爲可能出現越界錯誤是嘗試使用'array [1]'想法的一個好處,因爲它可能會捕獲尚未找到的一般'array [n]'代碼中的錯誤。 – us2012

+0

數組如何導致非非數組變量引起的切片?考慮到A來源於B.A a; B b,b2 [1]; b = a; b2 [0] = a;你可以在兩個任務中切分。你不會在B切片b3 & = a;但這是一個參考,這不是開場白的問題。多態性的推理也一樣。 –

8

聽起來像一個很好的策略,並沒有缺點。你明白地不是在C或C++中浪費內存。由大小爲1的數組所佔用的內存與由相同類型的變量所佔用的內存相同。

編譯器可能會生成微觀效率較低的代碼,但這實在不值得擔心。

7

該標準說你可以把一個不是數組的對象的地址作爲一個大小爲1的數組(這樣你可以把指針指向過去的結尾)。

見節中的C++ 11標準的§5.7.4:

對於這些操作符的目的,一個指向非數組對象 行爲相同的指針的第一個元素數組長度爲 ,對象類型爲元素類型。

0

這裏我們面對2個代碼塊。

  • 一大塊代碼,設計用於獲取數組並通過它工作 。
  • 一段代碼,它使用以前的代碼塊和 某些數據。

構造你的代碼。

大塊代碼應該是一個函數,可能分爲幾個子函數。 另一段代碼將調用此函數。

函數的參數。數組或單個字符。

(a) void work(char c); 
    (b) void work(char& c); 
    (c) void work(const char v[], size_t size); 
    (d) void work(  char v[], size_t size); 

選項(a)和(b)如樣的工作是沒有意義的用於陣列應當被使用。事實並非如此。
如果工作對陣列有意義,應使用選項(c)和(d)。因此,使用數組。

保存數據的變量。數組或單個字符。

如果你只需要保存一個字符,然後使用一個非數組字符。你仍然可以調用數組函數。

char c; 
c = 'b'; 
work(&c, 1); 
////// 
char a[1]; 
a[0] = 'b'; 
work(a, 1); 

功函數看到單變量和陣列尺寸1的陣列碼將在兩種情況下,用無效率涉及很好地工作。

測試

讓我們來看看實際的代碼保存我的以前的聲明。

#include <iostream> 
#include <ctime> 
#include <vector> 
#include <cstddef> 
#include <chrono> 

using namespace std; 

unsigned long miliTime() 
{ 
    return std::chrono::system_clock::now().time_since_epoch()/
      std::chrono::milliseconds(1); 
} 
// An hypotetical work function with arrays 
void workArray(char v[], size_t size) 
{ 
    for (size_t n=0; n<size; ++n) 
    { 
    // large block of code 
    for (int i=0; i<1000; ++i) 
    { 
     v[n] += 3 + i; 
     if (v[n] == '3') 
     v[n] = 'J' - v[n]; 
     v[n] = toupper(v[n]) + '-'; 
    } 
    } 
} 

// Same function just for a single character 
void workSingle(char& c) 
{ 
    // large block of code 
    for (int i=0; i<1000; ++i) 
    { 
    c += 3 + i; 
    if (c == '3') 
     c = 'J' - c; 
    c = toupper(c) + '-'; 
    } 
} 

int main(void) 
{ 
    const long int repeats =1000000; 
    long int n; 
    unsigned long start; 
    double dif; 

    start = miliTime(); 
    char c; 
    c = 'b'; 
    for (n=0; n<repeats; ++n) 
    workArray(&c, 1); 
    dif = miliTime() - start; 
    cout << "Result = " << c << endl; 
    cout << "Non-array var passed to array code = " << dif << " ms" << endl; 

    start = miliTime(); 
    char a[1]; 
    a[0] = 'b'; 
    for (n=0; n<repeats; ++n) 
    workArray(a, 1); 
    dif = miliTime() - start; 
    cout << "Result = " << a[0] << endl; 
    cout << "Array var passed to array code = " << dif << "ms" << endl; 

    start = miliTime(); 
    char c2; 
    c2 = 'b'; 
    for (n=0; n<repeats; ++n) 
    workSingle(c2); 
    dif = miliTime() - start; 
    cout << "Result = " << c2 << endl; 
    cout << "Non-array var passed to non-array code = " << dif << "ms" << endl; 

    start = miliTime(); 
    char a2[1]; 
    a2[0] = 'b'; 
    for (n=0; n<repeats; ++n) 
    workSingle(a2[0]); 
    dif = miliTime() - start; 
    cout << "Result = " << a2[0] << endl; 
    cout << "Array var passed to non-array code = " << dif << "ms" << endl; 
} 

當在GCC-4.7使用此命令行編譯並在我的電腦中執行:

g++ -O2 -Wall -std=c++11 x.cpp -o x.out && ./x.out 

我得到這樣的輸出:
結果= Z
非陣列VAR傳遞到陣列碼= 5520ms
結果= z
傳遞到陣列碼的數組var var = 5515ms
結果= z
非數組var pas SED非陣列碼= 5203ms
結果= Z
陣列變種傳遞給非陣列代碼= 5203ms

如所預期的結果總是相同的。 將數組或非數組變量傳遞給兩個實現的工作函數沒有任何重大差異。

workSingle比workArray快6%。
由於內循環執行1000次,外循環(不存在於workSingle中)的執行不太可能是原因。原因可能是由於訪問v [n]比訪問c慢,這是由於間接性。
儘管如果您在內部循環中更改從std :: cin讀取的全局變量的1000,那麼workSingle實際上會比workArray慢!

某些類型的優化,緩存未命中或其他低級別的東西可能是原因。我不會爲工作的不確定性而犧牲工作的可重用性。除非時間如此重要以至於你願意進入組裝階段,否則我不會犧牲工作的可重用性。

結論:

將變量聲明爲非數組,因爲它只需要保存一個字符。
將您的大部分代碼作爲採用數組參數的函數來實現。如果它很大,可能會分成幾個小節。

+0

我絕不會使用選項(b),因爲我不希望'work(foo)'修改foo。對於不熟悉'work()'的內部工作的讀者來說,這是一個地雷。如果你想修改一個參數,就這麼說,然後用'void work(char * c);'來請求一個指針。 「工作(&foo)」清楚地告訴讀者他應該期望foo改變。 – cmaster

+0

不,工作(&foo)不告訴讀者他應該期望foo改變。你需要檢查函數聲明和文檔。考慮void(const char * foo)。並且通過引用而不是指針傳遞是在C++中傳遞IN-OUT參數的常用方法。 –