2011-06-12 55 views
20

只是想知道是否有人會爲我確認一些別名規則。C++別名規則

我知道,混疊(即加載存儲問題)可能導致以下類型的代碼是次優的,因爲我們不能假設x, y, z不重疊:

// case 1: 
void plus(size_t n, double *x, double *y, double *z) 
{ 
    for (size_t i = 0; i != n; ++i) 
     z[i] = x[i] + y[i]; 
} 

我知道這有一個C關鍵字__restrict這暗示到,它不應該考慮重疊的情況下,編譯,因此潛在生成更好的代碼:

// case 2: 
void plus(size_t n, double *__restrict x, double *__restrict y, double *__restrict z) 
{ // as above... } 

但是別名如何處理C++風格的代碼,我們將在那裏處理通過引用傳遞的容器對象,而不是上面類似於C的示例中的原始指針?

舉例來說,我猜想會有走樣的問題,如果我們做了以下內容:

// case 3: 
void plus(std::vector<double> &x, std::vector<double> &y, std::vector<double> &z) 
{ // similar to above... } 

並移動到一個不太簡單的例子,這有什麼區別,如果基礎數據類型容器是不同的?在執行層面最集裝箱動態管理與指針存儲,所以它不是很清楚,我的編譯器如何能確保以下不別名:

// case 4: 
void foo(std::vector<mytype1> &x, std::vector<mytype2> &y) 
{ // interwoven operations on x, y... } 

我並不想對微型優化,但我想知道現在是否更好地將限制指針傳遞到容器周圍,而不是引用。

編輯:清除一些術語,如指出:restrict是C99關鍵字。在各種編譯器中也有__restrict__restrict__,但它們都做同樣的事情。

+0

對於容器的例子,除非'&x ==&y'我不相信它們有任何可以重疊的方式,假設符合標準的矢量實現。 – Sven 2011-06-12 07:52:05

+0

@Sven:不同的std :: vector不重疊,但是通常你可以通過引用傳遞任何對象類型,可能是重疊的。所以我希望編譯器需要確保正確性,並保守假設有別名。這就是爲什麼__restrict進來... – 2011-06-12 07:59:13

+0

@Darran:實際上編譯器會做矢量優化或什麼時候傳遞一個對象重載operator [],而不是一個實際的數組或指針?不知何故,我懷疑它。 – Sven 2011-06-12 08:09:03

回答

8

根據strict-aliasing rule,您不允許使用指向不同類型的指針(除char*和朋友之外)指定相同的內存,因此情況4只適用於其中一種類型爲char*的情況。

雖然標準沒有要求這樣做,並且實現可以隨意提供其他內容,但情況3與情況1並不完全不同,因爲引用是作爲所有編譯器上的指針實現的。

+0

我同意案例1和3與別名基本相同,但如果您按照案例3使用引用,則不能使用__restrict,這就是爲什麼我認爲通過限制指針傳遞容器可能會比引用更好... – 2011-06-12 08:04:34

+0

@達倫:C++標準甚至沒有提及'__restrict'關鍵字,它是一個MSVC擴展。也許你應該在這個問題上加上這一點。 – Xeo 2011-06-12 08:24:43

+0

感謝您提供嚴格的別名信息,這對我來說是新的。情況4可能是實際代碼中最常出現的情況,所以別名問題可能不會像我認爲的那樣頻繁發生。和__restrict或restrict,_restrict_等(正如我指出的)是一個C(99)關鍵字,但GCC和MSVC至少支持C++ – 2011-06-12 08:27:30

4

這對C++來說並不具體。考慮這個C99位:

struct vector { 
    double* data; 
    size_t n; 
}; 

void 
plus(struct vector* restrict x, struct vector* restrict y, struct vector* restrict z) 
{ 
    // same deal as ever 
} 

這裏,restrict購買我們很少:x->datay->dataz->data都是double*,並允許別名。這與使用限制時的情況1,,甚至完全相同。

如果有一個在C restrict關鍵字++(或使用分機時),最好的辦法可能會做plus(vecA.size(), &vecA[0], &vecB[0], &vecB[0]),使用相同的plus作爲案例2.而事實上,它可能現在這樣做的權利,使用沒有restrict的C89風格界面,但使用了封面下的關鍵字。

+1

你能定義類似struct vector {double * restrict data; //等等};在這種情況下,爲了防止混疊? – 2011-06-12 09:30:57

+0

@Darren你可以和它在這種情況下工作,但我認爲給定'void f(struct vector * x,struct vector * y)'然後'f(p,p)'是有問題的:'x-> data'將會是'double * restrict',但會替換'y-> data'(IIUC)。 「限制」似乎更像是一種保存特殊情況的有力工具,而不是萬能藥。 – 2011-06-12 09:35:28