2017-04-19 87 views
2

我試圖創建一個數組的字符串::大小的成員,但它抱怨在「char消息[msgSize]」表達式沒有評估一個常量。C++創建一個字符串::大小的數組

但是,它讓我聲明「msgSize」。

這怎麼可能?爲什麼我允許一個常量,但我不允許將它用於需要const的東西。

如果答案是:「該字符串的大小可能會改變」,那麼可以使用sizeof()的相同的參數,但這是有效的。

const unsigned int msgSize = 
     saveAs.size() + 
     sizeof("NOTE| sent get request to: ") + 10; 

    char message[msgSize]; 
    memset(message, 0, msgSize); 
    sprintf_s(message, msgSize,"NOTE| sent get request to: %s", saveAs.c_str()); 
    _cRec->output(message); 
+8

'sizeof'可以在編譯時進行評估,而'string.size()'不能。 – nwp

+8

「const」變量和常量表達式之間有一個重要的區別。 – aschepler

+0

'const'不是'constexpr'。如果你的編譯器可以認爲'const'是一個常量表達式,就像'sizeof'一樣,它可以讓你用它作爲'constexpr'變量,但是如果你拋出一個只有運行時的表達式,比如'saveAs。 size()' –

回答

1

那麼const只是意味着你保證價值不會改變。你甚至可以用const_cast來覆蓋它。

編譯器需要的是一個可以在編譯時評估的值。這是一個更強的要求。這些值用constexpr關鍵字標記。

不幸的是,你運氣不好,std::string ... size()不是constexpr

我打的following example

#include <iostream> 
#include <string> 
using namespace std; 

const string msg("Some msg"); 
constexpr int msg_len = msg.size(); 

int main() { 

    char msg[msg_len]; 

    cout << sizeof(msg); 
    return 0; 
} 

的事情是,size()不是constexpr,你不能讓一個stringconstexpr,因爲它有一個不平凡的析構函數。

爲什麼它的設計方式超出了我的想象。看起來像一個反直覺和嚴重的限制。但是,有很多巧妙的實現,例如小存儲優化。可能很難讓它們在執行過程中沒有發生嚴重的變化。

+0

_「爲什麼這樣設計的方式超出了我的範圍。」_當運行時涉及動態分配時,如何將'std :: string'變爲'constexpr'? –

+0

你讀過下面的句子嗎?有更多的實現,所以你的陳述並不普遍。問題是關於設計。你提供技術細節,這是一個後果。也許C++缺乏const字符串類型? – luk32

+0

沒有「更多的實現」; SSO存在,但在編譯時不可能知道它是否足夠或是否需要進一步調整大小。支持需要動態分配或無限的靜態分配空間。至於一個常量字符串類型,我希望看到;也許是圍繞'char [n]'的一些簡單的封裝。但是,這將是非常有限的。 –

0

你將不得不使你的數組​​變成動態的。 字符串的大小不知道在編譯時間,但只在運行時。

此外,您的列表不是一個最小的可編譯示例。我只能假設saveAs是一個std :: string。

下面將工作:

int main() 
    { 
     std::string myString("My string"); 
     char * myCStyleString = new char[myString.size()]; 

     delete[] myCStyleString; 
    } 

,因爲我們是動態分配數組那裏。

你想做什麼?看起來你只是想將一個文件名複製到一個消息字符串中。只要繼續使用std :: string;

int main() 
    { 
     std::string myString("My string"); 
     std::string message = "I like beans and rice with: "; 
     message += myString; 

     return 0; 
    } 

但我再次需要一個最小的可編譯示例來確定您的目標。

0

爲什麼我允許使一個常量,但我不允許使用它到 東西需要一個常量。

這是因爲您所擁有的「常量」表達式是由非常量部分組成的,即字符串類的大小方法。就編譯時已知的價值而言,它並不是真正的恆定值。

考慮在未來

使用constexpr變量/功能。如果回答是:「字符串的大小可能會改變」,那麼 相同的參數可以使用的sizeof()進行,但作品。

沒有相同的參數不能用於sizeof,因爲sizeof不需要它的參數是一個常量。


如果你知道一個事實,即saveAs包含已知大小的字符串,那麼也許它會如果你是大小聲明爲一個常量,然後參考它在你的計算是最好的:

constexpr unsigned int msgSize = 
     SAVEAS_SIZE + 
     sizeof("NOTE| sent get request to: ") + 10; 

那麼這將允許你這樣做:

char message[msgSize]; 
0

在C++中,你不能聲明VLA秒。

在聲明的陣列,例如:

char message[x]; 

表達x必須是在compile time有價值的,這是它的值具有當所述源被編譯成可以公知的。

在你例如:

char message[msgSize]; 

表達式(變量)msgSize不是在編譯時已知的,但僅在運行時。這是因爲編譯器必須知道堆棧中有多少字節。

注意:變量msgSize常數的值。常量值是而不是表達式在編譯時評估。它只是意味着它的價值一旦被分配就不能改變。

在C++ 11中引入了重要作品constexpr以定義一個應該在編譯時評估的表達式。

但在你的情況下,沒有辦法在編譯時獲得動態字符串的大小。所以你必須做的是使用動態數組(動態內存)。

char* message = new char[msgSize]; 
// now you have an array of msgSize lenght 
// ... do stuff... 
// do not forget to release the memory when end 
delete[] message; 

最後,我建議你重新闡述你的代碼,因爲它很可能你不需要字符的動態數組,而只是一個std::string。事實上,您可以使用重載運算符+來連接字符串,並使用方法std::string::c_str()作爲const char*來訪問以實現向後兼容。

0

你需要一個編譯時間常數char message[msgSize];,因爲這是它使用即在數據段分配靜態存儲器的局部變量,所以編譯器需要計算由代碼所需要的字節數,包括局部變量和數組。

您可以使用動態內存來解決您的問題。 動態內存分配在堆中。在C中,您應該使用malloc()。在C++中,您應該使用new[](或更好,std::vector或甚至std::string)。然後,您可以使用變量中的運行時值指定內存大小。

所以,你的代碼看起來更像如下:

char* message = new char[msgSize]; //Allocated memory 
//Do everything that you need... 
delete[] message; //Release memory 

或者:

#include <vector> 

std::vector<char> message(msgSize); //Allocated memory 
//Do everything that you need... 
相關問題