[英]Directly write into char* buffer of std::string
所以我有一個std::string
和一個 function,它接受char*
並寫入其中。 由於std::string::c_str()
和std::string::data()
返回const char*
,我不能使用它們。 所以我正在分配一個臨時緩沖區,用它調用 function 並將其復制到std::string
中。
現在我計划處理大量信息,復制此緩沖區會產生明顯的影響,我想避免它。
有人建議使用&str.front()
或&str[0]
但它會調用未定義的行為嗎?
不可能。 字符串可以在寫入時復制,因此它需要處理所有讀取和寫入。
在[string.require]中:
basic_string
對象中的類似於char的對象應連續存儲。 也就是說,對於任何basic_string
對象s
,對於所有n
值,標識&*(s.begin() + n) == &*s.begin() + n
都應成立,以使0 <= n < s.size()
。
因此&str.front()
和&str[0]
應該可以工作。
str.data()
, &str.front()
和&str[0]
起作用。
在這里 ,它說:
charT* data() noexcept;
返回:指針
p
,使得[0, size()]
每個i
具有p + i == &operator[](i)
。復雜性:固定時間。
要求:程序不得更改存儲
at p + size()
。
非常量.data()
可以正常工作。
最近的草案對.front()
措辭如下:
const charT& front() const;
charT& front();
要求:
!empty()
。效果:等同於
operator[](0)
。
以及以下用於operator[]
:
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
要求:
pos <= size()
。
*(begin() + pos) if pos < size()
返回*(begin() + pos) if pos < size()
。 否則,返回到類型的對象的參考charT
與值charT()
其中,修改所述對象導致未定義的行為。拋出:沒事。
復雜性:固定時間。
因此,它使用迭代器算法。 因此我們需要檢查有關迭代器的信息。 在這里 ,它說:
3 basic_string是一個連續的容器([container.requirements.general])。
所以我們需要去這里 :
連續容器是支持隨機訪問迭代器([random.access.iterators])且其成員類型
iterator
和const_iterator
是連續迭代器([iterator.requirements.general])的容器。
然后在這里 :
對於整數值n和可引用的迭代器值
a
和(a + n)
,*(a + n)
等於*(addressof(*a) + n)
的要求進一步稱為迭代器。
顯然,連續的迭代器是在這些 論文中添加的C ++ 17功能。
該要求可以重寫為:
assert(*(a + n) == *(&*a + n));
因此,在第二部分中,我們取消引用迭代器,然后獲取它指向的值的地址,然后對其進行指針算術,然后對其進行解引用,這與遞增迭代器然后對其進行解引用相同。 這意味着連續的迭代器指向每個值緊接存儲的內存,因此是連續的。 由於采用char*
函數需要連續的內存,因此您可以將&str.front()
或&str[0]
的結果傳遞給這些函數。
您可以簡單地將&s[0]
用於非空字符串。 這為您提供了指向緩沖區開始的指針
當您使用它放置n個字符的string
的長度(不僅是容量)必須事先至少為n ,因為無法在不破壞數據的情況下進行調整。
即,用法可以像這樣:
auto foo( int const n )
-> string
{
if( n <= 0 ) { return ""; }
string result( n, '#' ); // # is an arbitrary fill character.
int const n_stored = some_api_function( &result[0], n );
assert( n_stored <= n );
result.resize( n_stored );
return result;
}
自C ++ 11以來,此方法已正式生效。 在此之前,在C ++ 98和C ++ 03中,不能正式保證緩沖區是連續的。 但是,對於實際做法,該方法自C ++ 98(第一個標准)以來一直有效-可以在C ++ 11中采用連續緩沖區要求的原因(它在Lillehammer會議中添加,我認為那是2005年) )是因為沒有不連續的字符串緩沖區的現有標准庫實現。
關於
” C ++ 17在
std::string
添加了非常量data()
,但它仍然說您不能修改緩沖區。
我不知道有任何這樣的措辭,因為那樣做會破壞非const data()
的目的,所以我懷疑這一說法是正確的。
關於
”現在,我計划使用大量信息,復制此緩沖區將產生明顯的影響,我想避免這種情況。
如果復制緩沖區有明顯的影響,那么您要避免無意中復制std::string
。
一種方法是將其包裝在不可復制的類中。
我不知道您打算如何使用該string
,但是如果
您只需要一個char緩沖區即可自動釋放自己的內存,
然后我通常使用vector<char>
或vector<int>
或任何類型
您需要的緩沖區。
以v
為向量,可以保證&v[0]
指向
可以用作緩沖區的順序存儲器。
注意:如果您認為 string::front() 與 &string[0] 相同,那么以下是多余的答案:
根據cplusplus的說法:在 C++98 中,你不應該寫 to.data() 或 .c_str(),它們將被視為只讀/常量:
程序不得更改此序列中的任何字符。
但在 C++11 中這個警告被移除了,但是返回值仍然是 const,所以官方也不允許在 C++11 中。 因此,為了避免未定義的行為,您可以使用string::front() ,它:
如果字符串 object 是 const 限定的,則 function 返回 const char&。 否則,它返回一個 char&。
因此,如果您的字符串不是 const,那么正式允許您操作 string::front() 返回的內容,這是對緩沖區第一個元素的引用。 但是鏈接沒有提到這適用於哪個 C++ 標准。 我假設 C++11 及以后。
此外,它返回第一個元素,而不是指針,因此您需要獲取它的地址。 目前尚不清楚您是否被正式允許將其用作整個緩沖區的 const char* ,但結合其他答案,我確信它是安全的。 至少它不會產生任何編譯器警告。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.