[英]Constructor being called when trying to use strtok
我編寫了一個名為 DSString 的自定義字符串類,其中包含一個私有成員 char* 數據。 我正在嘗試解析 csv 文件中的行,將在文件行中找到的每個單詞添加到 std::set 的 DSString 對象。 我調用 getline 將文件中的一行讀入 char* 緩沖區,然后調用 strtok 獲取單詞。 但是,下面的while循環不起作用; 我的調試器告訴我,在到達那行代碼時,它使用參數 NULL 調用 DSString.h 中的構造函數,然后程序結束。
int main (int argc, char ** argv) {
ifstream input;
input.open(argv1);
int reviewLinesCtr = 0;
char line[16000];
set <DSString>positiveWordSet;
while (input.getline(line,16000)) {
if (reviewLinesCtr == 10) break;
//Push review to positive set
DSString word = strtok(line, " ");
while (word != nullptr) { //Program ends abruptly here
positiveWordSet.insert(word);
word = strtok(nullptr, " ");
}
}
reviewLinesCtr++;
}
return 0;
}
DSString 只有私有成員char *data
和int size
。 這是 DSString 中的相關代碼:
DSString::DSString(const char* param) { //This is the constructor being passed, param = NULL, which crashes the program.
data = new char[strlen(param) + 1];
this->size = strlen(param) + 1;
strcpy(data, param);
}
DSString& DSString::operator= (const char* source) {
if (data != nullptr) {
delete[] data;
}
data = new char[strlen(source + 1)];
size = strlen(source) + 1;
strcpy(data, source);
return *this;
}
bool DSString::operator!= (const DSString& rhs) const {
if (strcmp(this->data, rhs.data) != 0) {
return true;
}
else {
return false;
}
}
這是大學項目的一部分,因此我們需要實現自定義 DSString 類。 否則我不會使用它,而是使用 std::string。 除了要從文件中讀取的緩沖區外,我們也不能在程序中的任何地方使用 char*。 當我嘗試開始執行此 while 循環時,為什么會調用此構造函數並將其指定為 NULL 作為參數? 我該如何解決?
如果這是一個重復的問題,我深表歉意,我已經在互聯網上搜索了一段時間,但沒有找到任何有助於解釋這里發生的事情的信息。 任何幫助,將不勝感激。
崩潰的原因很可能在 eeorika 的回答中有所概述。 沒有必要在這里重復。
DSString word = strtok(line, " ");
是Copy Initialization ,因此調用的是構造函數,而不是賦值運算符。
還有一個致命的錯誤。 由於strtok
在沒有更多標記時返回nullptr
如果沒有更多標記,將DSString::DSString(const char* param)
並且
data = new char[strlen(param) + 1];
將在空指針上調用strlen
。 卡布姆。
解決方案:在const char *
變量中捕獲strtok
的返回值並測試它是否為nullptr
。 只有在有令牌時才繼續構建。
由於分配要求是您不能使用char *
變量,因此請確認您是否可以使用const char *
。 如果沒有,那是一種有趣(而且非常愚蠢)的泡菜。
賦值運算符泄漏內存。
DSString& DSString::operator= (const char* source) {
delete[] data; // must release the object's current string
// before allocating a new one
data = new char[strlen(source + 1)];
size = strlen(source) + 1;
strcpy(data, source);
return *this;
}
DSString word = .... while (word != nullptr) { //Program ends abruptly here
在這里,您將DSString
對象與nullptr
進行比較。 讓我們看看操作符過載:
bool DSString::operator!= (const DSString& rhs) const {
它接受一個DSString
引用,而不是一個指針。 但是,您的類可以從指針隱式轉換,因此可以從std::nullptr_t
間接轉換,因為它有一個轉換構造函數:
SString::DSString(const char* param) { //This is the constructor being passed, param = NULL, which crashes the program.
由於構造函數調用strlen(param)
和strcpy(data, param);
,將 null 傳遞給該構造函數具有未定義的行為。
為避免使用隱式轉換意外調用此構造explicit
,您應該將其聲明為explicit
。
將 null 傳遞給構造函數在這里也是一個問題: DSString word = strtok(line, " ");
.
要修復邏輯,您應該使用帶有strtok
的指針,並且只有在您檢查它是非空后才創建您的字符串:
char* word = strtok(line, " ");
除了要從文件中讀取的緩沖區外,我們也不能在程序中的任何地方使用 char*。
坦率地說,使用strtok
而不是使用char*
只是愚蠢的要求。
好像你已經違反了這個要求:
DSString
只有私有成員char *data
和 ...
無論如何,如果您需要遵循此類限制,則需要更改構造函數以在傳入 null 時正確運行。 具體來說,在這種情況下,它可能不會將該指針傳遞給具有未定義行為的函數。
並且,如果您將成員設置為空,那么您還必須在將其傳遞給上述此類函數之前檢查該成員是否為空。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.