2014-02-13 30 views
6

我今天遇到了很多麻煩,跟蹤了一個真正逃避腐敗的錯誤。
我想如果我真的注意到了警告,我不會很難找到它,但是因爲我沒有找到相關信息,說明爲什麼這個特定的警告彈出,我讓它滑動,這是一個錯誤。對齊方式:警告C4316在所有課程中有對齊的成員

因此,這裏的牽連警告的Visual Studio 2013給我:

warning C4316: object allocated on the heap may not be aligned 16 

並將它傳遞的對齊(16)臨時當通過const引用一個構造函數,如下面的代碼生成演示了:

class Vector 
{}; 

__declspec(align(16)) class VectorA 
{}; 

class Shape 
{ 
public: 
    Shape(const Vector& vec) {} 
}; 

class ShapeA 
{ 
public: 
    ShapeA(const VectorA& vec) : mVec(vec) {} 

private: 
    VectorA mVec; 
}; 

int main(int argc, char *argv[]) 
{ 
    Shape* shape = new Shape(Vector()); // ok 
    ShapeA* shapea = new ShapeA(VectorA()); // warning C4316: 
          // object allocated on the heap may not be aligned 16 
} 

這帶來幾個問題:

  1. 一我不負責所述結構的對齊(它來自一個庫),我無法真正對此產生影響。解決此問題的建議方法是什麼?

  2. 由於這是一個警告,我猜測它不會有戲劇性的效果。但是我發現的效果非常戲劇化和沉默(這隻會在將一個完全不相關的float引用傳遞給sqlite函數時出現)。(編輯:這實際上是錯誤的,堆沒有因此而被破壞)是否真的如此簡單:「此代碼肯定會導致堆損壞,不要這樣做。」 ?或者是否有更復雜的行爲鏈來引起這樣的事情?我想到的

一個解決辦法是有一個的unique_ptr來對齊對象,而不是有它作爲一個直接的成員,但我有點捨不得無處不添加的unique_ptr我收到平原結構(即使它讓我PIMPL我的代碼)

附錄

事實證明我是繼承類VectorA它確實提供了新的刪除重載保證適當的調整,但我自己的子類沒有。但是,此警告在未來一段第二,發生難度更棘手擺脫:

擴展

另一種情況產生的警告是:

__declspec(align(16)) class VectorA 
{ 
    void* operator new(size_t size) 
    { 
     void* p = _aligned_malloc(size, 16); 
     if(p == 0) throw std::bad_alloc(); 
     return p; 
    } 

    void operator delete(void *p) 
    { 
     VectorA* pc = static_cast<VectorA*>(p); 
     _aligned_free(p); 
    } 
}; 

class ShapeB 
{ 
public: 
    ShapeB() {} 

private: 
    VectorA mVec; 
}; 

int main() 
{ 
    std::unique_ptr<BoxShapeB> shapeb = std::make_unique<BoxShapeB>(); 
} 

似乎任何一類我的例子中有一個對齊的成員,在實例化時也會產生警告。就像我上面所說的去除警告的方法是指向這些成員。 這個警告並沒有發生在先前版本的Visual Studio中,代碼相同,所以我的問題是:上面的錯誤程度如何,應該不惜一切代價避免?即我應該如何提出警告?

假設我的大多數類都有一個共同的基類Object,並且我的大多數類都將align(16)Vector作爲成員對齊,是否值得將這個重載的new和delete放在這個基類中,而忘記了把我的所有成員矢量指向指針?這種方法會起作用嗎?

回答

2

這個問題並沒有像你所建議的那樣通過const引用傳遞對齊結構。 See this documentation of C4316。問題是你聲明瞭對齊的結構,但不提供處理這種對齊的合適的新/刪除操作符。

如果你得到第三方庫,它是預建那麼恕我直言,你應該報告的請求,以它的作者來解決這個問題這樣的情況。如果你可以自己建立這個庫,那麼你可以自己添加提到的操作符。

+0

是的,你是對的,它並不是因爲圖書館沒有提供新的/刪除,而是因爲我將它子類化,並沒有在我自己的子類中提供它們。但第二個問題仍然存在,所以我將重新制定。 – MONK

+0

將對齊的類作爲其他類中的成員將生成警告(與第一個相反,即使在定義新的刪除過載以確保對齊時也會如此) – MONK

+0

@MONK我認爲第二個問題與第一個類似。在第一個中,你繼承了對齊的結構並需要適當的操作符。我想第二種情況是一樣的。但這只是一個猜測。 – Bogdan

1

所以有點帶記憶博士和整體解決錯誤的會話擺弄之後,事實證明:

  1. 堆並沒有因爲定位問題是腐敗。這意味着我仍然不知道這個警告應該在多大程度上令人擔憂,但我選擇瞭解決方案來解決它:

  2. 至於避免這個警告,我已經使用了以下解決方案,讓我滿意現在:創建一個類Align16,它重載所有新的和刪除操作符以使用_aligned_malloc和_aligned_free。然後每個包含對齊成員的類都必須從Align16繼承,以使警告消失。
    因爲_aligned_malloc,我知道它不可移植,所以如果我想讓我的代碼是可移植的,Bullet Physics有一個自定義的實現,它可以在其內存分配器中工作,如果需要的話,我可以重新使用它。

+0

您是否嘗試修改項目的C++代碼生成參數中的Struct Member Alignment參數?您可以將它設置爲16字節用於整個項目。 –