2011-03-11 48 views
2

我正在執行代碼審覈以解決很少發生的實時環境問題。它在調試環境中不可重現,因此調查的唯一方法是實時環境和代碼分析的核心轉儲。這是形勢的總結:
核心轉儲:關於涉及字符串類的核心轉儲問題的幫助

(gdb) bt 
#0 in strlen() from /lib/libc.so.6 
#1 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string$base() from libstdc++.so.6 
#2 in CustomStr::CustomStr() 

代碼必須在標準的包裝類:: string類,類似:

class CustomStr: public string 
{ 
    //Some custom members here 

}; 

This custom class has constructors: 
CustomStr::CustomStr(const char *str):string(str) 
{ 
    //Some derived class inits 
} 

CustomStr::CustomStr(const CustomStr& str) : string(str.c_str()) 
{ 
    //Some derived class inits 
} 

我認爲這兩個構造函數有一個問題,如果一個指向NULL的指針被傳遞,同樣的將被傳遞給String構造函數,並且當它在內部調用strlen()來確定長度時會發生未定義行爲(UB)。 我想實現正確的方式將是調用字符串構造像以前一樣,檢查是否有NULL:

CustomStr::CustomStr(const char *str) 
{ 
    if(str!= NULL) 
     string(str); 
    //Some derived class inits 
} 

CustomStr::CustomStr(const CustomStr& str) 
{ 
    if(str!= NULL) 
     string(str.c_str()); 
    //Some derived class inits 
} 

我的問題是:

  1. 做的問題(我認爲這是)並且提出的解決方案似乎是有效的案例?
  2. 字符串構造函數檢查NULL嗎?我認爲這應該是因爲它內部調用strlen()將顯示UB NULL。
  3. 除了NULL檢查一個如何檢查是否有效的爲const char *被傳遞?(非NULL終止爲const char *等)

回答

2

來自const char *的構造函數不檢查空指針,它由調用者檢查是否需要。您必須知道是否有可能使區段爲空。

其他構造函數可以使用字符串的複製構造函數,而不是將c_str()傳遞給它。它既可以避免重新計算長度,也可以用於空字符串。

0

到的std :: string(爲const char *)的參數應該是一個指向\ 0終止字符串的指針。 NULL不指向任何東西,當然也不是以null結尾的字符串。因此,傳遞NULL是違反前提條件的。

調試版本應該聲明指針不是NULL,因爲std::string是一個將被新手使用的類。它不應該在運行時檢查,因爲無論如何沒有有效的程序傳遞NULL。

像往常一樣在C++中,沒有辦法測試指針是否「有效」。如果一個機制是強制性的可以回答這個問題,C++將會導致顯着的性能處罰。

1

核心轉儲的進一步調查應該會給你一個關於導致崩潰的原因的精確圖片。特別是,究竟是什麼異常被拋出?如果它是一個訪問衝突(aka segfault),那麼轉儲也應該告訴你正在訪問哪個錯誤的地址,這反過來會告訴你,你的問題是從NULL指針還是其他地方讀取。

肯定有可能是一個指向std::string構造函數的NULL指針可能是你的問題,但是你不應該假設 - 核心轉儲的目的是從這種調試中剔除猜測。

在任何情況下,是的,std::string只是如果你從NULL指針構造它,所以你應該在將任何指針傳遞給字符串構造函數之前對它們進行NULL檢查。

class CustomStr : public string 
{ 
    CustomStr(const char *str) : string(str ? str : "<INVALID>") { .. } 
}; 

會是一個簡單的解決方法。

+0

這背後的想法是,我永遠不會傳遞一個空指針:-),不應該從檢查中得到性能損失。你不能把它強加給每個人,只是爲了節省一些新手。如果你需要檢查,你可以在調用構造函數時自己添加它。 – 2011-03-11 10:23:47

+0

爲了好奇,我在上週做了一個關於核心轉儲的整整一個小時的會議講座:http://bit.ly/hPCmVW – Crashworks 2011-03-11 10:25:31

+0

@Bo Persson:當然,您可以使該檢查成爲僅調試斷言,或者只是激發傳遞NULL指針的人,等等。重要的是看看垃圾場,確定這確實是問題,而不僅僅是假設。 (儘管說實話 - 我說這是我的團隊的官方Perf Nazi - 即使在RISC芯片上,在這種情況下執行NULL檢查的性能懲罰也非常小,因爲您可以將其作爲無分支條件移動在大約三個流水線週期中)。 – Crashworks 2011-03-11 10:27:32

0

你不應該從一個標準的庫類派生,他們沒有虛擬析構函數,它們不是基類。

也許這不是你有的問題,但它是很好的知道。不要這樣做。

你可以有一個std :: string作爲包裝類的組合。或者,正如我所發現的,根本不用std :: string類的任何包裝,這會導致更多的問題而不是解決一些問題。

你也許可以使用一些外部的功能,如果你需要像一些特定的功能「修剪」等。

這是很好的知道,在Boost庫很多字符串處理函數的存在。

+0

同意從容器類派生它通常不是一個好主意,但是非虛擬析構函數是一個問題**只有**如果通過指向std :: string的指針刪除CustomStr。低風險,是我的猜測。 – 2011-03-11 10:29:39

2

C++標準要求傳遞給std::string(const char*)的指針不是空指針(C++ 0x draft n3092中的§21.4.2)。所以字符串類本身不會檢查這種情況,而傳入null意味着你的代碼不符合。

你修好了CustomStr(const char*)看起來沒問題,但是CustomStr(const std::string&)的那個不是。參考不能爲空。 (如果編譯的話,我會感到驚訝)。

現在有方法檢查除了空檢查之外,隨機char*是否是「有效」的。