2012-08-09 38 views
1

我正在讀此pull request on dablooms返回值或直接在給定的輸出參數上寫入它會更好嗎?

最糟糕的是,摩摩爾不返回堆棧/寄存器中的散列值,而是直接將其寫入到提供的緩衝液中。這使得使用大量隨機數據填充bloom-> hashes緩衝區並逐步執行模塊化變得非常容易。

for (i = 0; i < bloom->nsalts; i++, hashes += 4) { 
    MurmurHash3_x64_128(key, key_len, bloom->salts[i], hashes); 
    hashes[0] = hashes[0] % bloom->counts_per_func; 
    hashes[1] = hashes[1] % bloom->counts_per_func; 
    hashes[2] = hashes[2] % bloom->counts_per_func; 
    hashes[3] = hashes[3] % bloom->counts_per_func; 
} 

我最近注意到,一些圖書館(至少在C++中,我的知識是漂亮,我很是新手限制)似乎並沒有返回值,但,而不是期望的輸出參數上,他們將寫出結果。我比較習慣看到這樣的事情:

Matrix leftOperand = { /* some values */ }; 
Matrix rightOperand = { /* some values */ }; 
Matrix result; 
result = multiplyMatrices(leftOperand, rightOperand); 

resultmultiplyMatricesreturn值。但學習使用OpenGL,GLEW和freeglut在我最近的項目,我不是這樣的不通話時看到更多的時候:

Matrix leftOperand = { /* some values */ }; 
Matrix rightOperand = { /* some values */ }; 
Matrix result; 
multiplyMatrices(leftOperand, rightOperand, result); 

我明白它做什麼,但我覺得符號爲奇數。然而,我越來越頻繁地看到這一點,當我看到上述拉申請的作者'讚美'時,我認爲可能有充分的理由這樣做。

因此,爲了寫出更少的糟糕和難聞的代碼,我想知道這是否是一種好的做法。我認爲它必須是出於性能方面的原因,但我不清楚從堆棧中壓入/彈出是否比直接寫入給定內存地址要慢。

我正在尋找一些指導原則,使用一種優於另一種。

+0

您特別感興趣哪種語言? – 2012-08-09 09:34:50

+0

@DanPuzey第一個例子是在C中,但我的用例是C++和Java。 – AntoineG 2012-08-09 10:12:52

回答

1

讓我們用C一個簡單的例子:

struct X 
{ 
    /* a lot of data */ 
}; 

struct X func1(/*args*/) 
{ 
    struct X result; 
    /* fill in result */ 
    return result; 
} 

int func2(/*args*/, struct X *result) 
{ 
    if (result == NULL) 
     return -1; 
    /* fill in *result */ 
    return 0; 
} 

/* in the code */ 
struct X x; 
x = func1(/* args */); 
func2(/* args */, &x); 

func1,填寫必要的數據了自己的堆棧幀,那麼該行x = func1(...)其複製到xfunc2得到指針x作爲它的參數和填充它

正如你可以在這裏看到,在使用func1兩個缺點:

  1. 您不能報告錯誤,除非設置x爲無效狀態(對於所有結構體(例如矩陣)可能不存在)
  2. 您必須複製可能的大量數據。

在某些情況下,錯誤可能根本不可能,因此第1點可能不一定成立。但是,如果你的結構很大,第二點就是性能殺手。

現在想象一下,在C++中一樣,只不過struct X現在class X,用拷貝構造函數和裏面一堆std::stringstd::list等。使用func2的性能增益變得更大,因爲複製類X的對象現在需要調用多個複製構造函數,深度複製所有內容,然後破壞func1內的本地對象。 (對於C++ 11來說,這會更壞(與C中一樣壞),因爲對象可以被移動)。

想要使用func1的唯一原因是可讀性和易寫性。例如,比較這:

string fix(const string &s); 
void print(const string &s); 

string str; 
print(fix(str)); 

VS此:

void fix(const string &s, string &res); 
void print(const string &s); 

string str; 
string fixed; 
fix(str, fixed); 
print(fixed); 

第一個是顯然更可以理解的,而第二個是更有效的。請注意,在像C這樣的語言中,第一個代碼的等價物可能導致內存泄漏,所以它甚至不可能。

所以這個問題歸結爲你更關心這兩個問題中的哪一個。如果你和一個Java人談話,他們可能會告訴你「性能差異很小,你甚至不會注意到它」。如果你和一個C語言傢伙交談,他們可能會告訴你「在性能上的差異可能會很小,但是這並不意味着你可以去做不必要的事情」。

在你提到的帖子中,程序員正試圖提高庫的性能。他正在改進的功能是「填充緩衝區」。這迫切需要通過緩衝區作爲參數:

  • 您不需要的內容複製緩衝區
  • 您可以提供您自己的緩衝區,無論是靜態還是動態分配的。
    • 的功能並不需要每次都
    • 分配內存,您可以重用緩衝區,而無需重新分配內存
    • 如果靜態分配的,你不需要釋放緩衝區
  • 您可以部分填寫更大的緩衝區
+0

在C++中,假設存在Exceptions(覆蓋錯誤報告情況),並且可以使用樣式調用: 'result.multiply(操作數);'(也可以返回-1而不是拋出異常) 而不是: '乘(操作數,結果);'(返回-1和/或拋出異常) ...在這兩種情況下'結果'已經初始化但不被操作複製。仍然會有使用第二種形式的論據嗎? – AntoineG 2012-08-09 10:19:10

+0

@AntoineG,首先,例外是​​[不是一個好主意](http://stackoverflow.com/q/1744070/912144)。其次,你最初的例子是:'result = multiplyMatrices(leftOperand,rightOperand);'。我非常懷疑有人會寫:'result.multiplyMatrices(leftOperand,rightOperand);'!一般情況下,如果所有的'result = func()'都可以轉化爲'result.func()',那麼就沒有區別了(甚至可能比'func(&result)'更快),但情況並非總是如此。 – Shahbaz 2012-08-09 10:29:00

+0

@AntoineG,更重要的是,dablooms項目是在C! – Shahbaz 2012-08-09 10:30:27

相關問題