簡體   English   中英

直接寫入 std::string 的 char* 緩沖區

[英]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]但它會調用未定義的行為嗎?

C ++ 98/03

不可能。 字符串可以在寫入時復制,因此它需要處理所有讀取和寫入。

C ++ 11/14

在[string.require]中:

basic_string對象中的類似於char的對象應連續存儲。 也就是說,對於任何basic_string對象s ,對於所有n值,標識&*(s.begin() + n) == &*s.begin() + n都應成立,以使0 <= n < s.size()

因此&str.front()&str[0]應該可以工作。

C ++ 17

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])且其成員類型iteratorconst_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM