2016-12-27 57 views
1

我的類中有多個需要const char *的方法,所以我將字符串轉換爲const char *,並將其存儲在類型爲local的變量中const char *。局部變量在構造函數中有效。但是,當我在同一個類的方法上調用它時,它是空的。轉換std :: string爲const char *和函數調用

如果我使用const引用傳遞它,我的問題已修復,但我期望我的代碼在不使用const引用的情況下工作。

我跟着How to convert a std::string to const char* or char*?爲其他方法將字符串轉換爲const char *。我認爲c_str()正確地轉換字符串。

我想了解導致我的本地變量爲空的根本原因。 我爲我的問題準備了示例代碼。

代碼問題:

#include <iostream> 
#include <string> 

using namespace std; 

class Config{ 
string strFileName_ = "/path/filename.ext"; 
public: 
    string getFileName() {return strFileName_;} 
}; 


class Loader{ 
const char * className_; 
public: 
    Loader(string name){ 
     //className_ = name.c_str(); //same result with .data() 
     className_ = name.data(); 
     cout << "[inside Loader constructor]className_ is:" << className_ << endl; 
    } 

    void loadFile(){ 
     cout << "[inside loadFile] className_ is:" << className_ << endl; 
    } 
}; 

int main(){ 
    Config cfg; 
    Loader ld(cfg.getFileName()); 
    ld.loadFile(); 
} 

代碼字符串,而不是爲const char *不存在這個問題。正如我所解釋的,如果我使用const引用,問題就不存在了。 代碼引用:

#include <iostream> 
#include <string> 

using namespace std; 

class Config{ 
string strFileName_ = "/path/filename.ext"; 
public: 
    const string &getFileName() {return strFileName_;} 
}; 


class Loader{ 
const char * className_; 
public: 
    Loader(const string& name) { 
     className_ = name.c_str(); 
     cout << "[inside Loader constructor]className_ is:" << className_ << endl; 
    } 

    void loadFile(){ 
     cout << "[inside loadFile] className_ is:" << className_ << endl; 
    } 
}; 

int main(){ 
    Config cfg; 
    Loader ld(cfg.getFileName()); 
    ld.loadFile(); 
} 
+0

請告訴我爲什麼你不能只使用'std :: string'?使用'const char *'有什麼好處? –

+0

您的意思是「它是空的」是什麼意思?它是'NULL'還是'nullptr'?你在使用什麼平臺/ C++編譯器/運行時?根據[C++標準(C++ 14)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf),'name.data()'應該返回一個「分配副本」:*指向分配副本 的第一個元素,該元素的第一個元素由'str.data()'的原始值 指向的數組*由於它是分配副本, 'd認爲無論新的obect的構造函數完成後源'string'對象發生了什麼,它都應該是有效的。 –

+0

我需要const char *因爲我使用需要這種格式的PETSc庫。但是,我的問題與PETSc庫無關,而且一般。 –

回答

4
Loader(string name){ 
    //className_ = name.c_str(); //same result with .data() 
    className_ = name.data(); 

的 「病根」 是由c_str()data()返回的指針指向由012擁有的數據。當std::string被破壞時,指針不再有效。它消失了。其內容不復存在。加入了無形的合唱團。已經無法與其製造商見面了。這是一個前指針。

這裏,string name是傳值參數給構造函數。當構造函數返回時,該參數被破壞。通過c_str()data()保存的指向其內容的指針不再是有效的指針。

對象的範圍和生命週期是C++的一個關鍵的基本原理。您必須完全理解何時以及如何創建或銷燬各種對象。與其他語言(如Java)不同,C++不會爲您管理它。您必須瞭解C++程序中的各種對象何時被銷燬,並且出於某些原因;以及由此產生的後果。在這裏,結果是保存的指向對象內部內容的指針會自動失效。隨後使用該指針會產生未定義的結果。

+0

這就是我的想法。但是當我看着C++標準(誠然C++ 14)時,它指出'data()'返回一個指向字符串「分配副本」的指針(參見上面的註釋)。行爲是否改變了C++ 14,還是我誤讀了一些東西? –

+0

沒有什麼變化。 「Allocated」指的是爲字符串分配的內部緩衝區「std :: string」。當std :: string被破壞時,它會銷燬其內部分配的緩衝區。 –

+0

@AndrewHenle:查看「通用需求」(位於'[string.require]')下的字符串部分的開始部分:'引用元素的引用,指針和迭代器...可能會被...無效非const成員函數......析構函數就是這樣的一個例子。 – Hurkyl

1

更好地利用這一點:

class Config{ 
     string strFileName_ = "/path/filename.ext"; 
    public: 
     string getFileName() { return strFileName_; } 
    }; 


    class Loader{ 
     string className_; 
    public: 
     Loader(string name){ 
      //className_ = name.c_str(); //same result with .data() 
      className_ = name.data(); 
      cout << "[inside Loader constructor]className_ is:" << className_ << endl; 
     } 

     void loadFile(){ 
      cout << "[inside loadFile] className_ is:" << className_ << endl; 
     } 
    }; 

    int main(){ 
     Config cfg; 
     Loader ld(cfg.getFileName()); 
     ld.loadFile(); 
    } 

否則,如果你真的想用三分球發揮:

class Config{ 
     string strFileName_ = "/path/filename.ext"; 
    public: 
     string getFileName() { return strFileName_; } 
    }; 


    class Loader{ 

     char *className_; 

    public: 
     Loader(string name){ 

      className_ = new char[name.size() + 1]; 
      std::copy(name.begin(), name.end(), className_); 
      className_[name.size()] = '\0'; // don't forget the terminating 0 

      cout << "[inside Loader constructor]className_ is:" << className_ << endl; 
     } 

     void loadFile(){ 
      cout << "[inside loadFile] className_ is:" << className_ << endl; 
delete []className_; 
     } 
    }; 

    int main(){ 
     Config cfg; 
     Loader ld(cfg.getFileName()); 
     ld.loadFile(); 
    } 
相關問題