公司的C++工程遷移到了Centos8上面。現進行警告消除。發現如下警告。覺得挺有意思的記錄一下。
Centos版本:
cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
Gcc版本:
gcc --version
gcc (GCC) 8.3.1 20191121 (Red Hat 8.3.1-5)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
警告提示:
‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘class upoData’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Wclass-memaccess]
代碼
memcpy ( &upoData[i] , &pData , sizeof ( UData ) ) ;
目前查出來的原因是,memcpy 會按照內存寫入數據。並不會執行拷貝構造函數。當執行拷貝操作時,拷貝指向的類或者結構體如果存在指針,
並且指針指向了動態申請的對象或者數組。此指針將被拷貝源的指針覆蓋。而當程序退出時,這部分被覆蓋的數據將造成數據泄露。
這類警告應該屬於編碼錯誤。
示例程序如下:
1 #include <cstring> 2 3 struct A 4 { 5 A(int size) : size_(size), data_(new int[size]) {} 6 ~A() { delete [] data_; } 7 8 // The copy constructor and the copy assignment operator need 9 // to be implemented for the class too. They have been omitted 10 // to keep the code here minimal. 11 12 int size_; 13 int* data_; 14 }; 15 16 int main() 17 { 18 A a1(10); 19 A a2(20); 20 std::memcpy(&a1, &a2, sizeof(A)); 21 22 // When we return from the function, the original data_ of a1 23 // is a memory leak. The data_ of a2 is deleted twice. 24 25 return 0; 26 }
執行完拷貝時,此時a1.data_已經被a2.data_所覆蓋,a1實例化時申請的int數組已經沒有指針指向它(第五行代碼)。程序退出時。這部分內存溢出。
解決方案,目前還沒有決定用哪個:
1.重寫類,使用拷貝構造函數,棄用memcpy。
優點,就應該這么辦,缺點,工程量有點大,老代碼,沒有敢動。
2.MakeFile中添加[-Wclass-memaccess]將警告屏蔽。
優點,修改的時間快。
缺點,不講武德,欺騙客戶。
3.強制類型轉換
memcpy ( &upoData[i] , &pData , sizeof ( UData ) ) ;---->memcpy ( (void*)&upoData[i] , (void*)&pData , sizeof ( UData ) ) ;
優點,修改的時間快。相比第二種看着舒服點。
缺點,也不太講武德,有點欺騙客戶和編譯器感情。
目前調查出三種修改方案。具體采用哪種定下來再補充。
參考鏈接:
c++ - What uses are there for "placement new"? - Stack Overflow
c++ - Using std::memcpy to object of non-trivially copyable type - Stack Overflow
c++ - Avoid `-Wclass-memaccess` on memcpy of a POD type w/copy disabled - Stack Overflow