直接写入std :: string的char * buffer

时间:2016-08-29 07:26:45

标签: c++ string c++14 language-lawyer c++17

所以我有一个std::string并且有一个函数需要char*并写入它。由于std::string::c_str()std::string::data()返回const char*,我无法使用它们。所以我分配了一个临时缓冲区,用它调用一个函数并将其复制到std::string

现在我计划处理大量信息,复制此缓冲区会产生明显的影响,我想避免它。

有些人建议使用&str.front()&str[0],但会调用未定义的行为吗?

3 个答案:

答案 0 :(得分:17)

C ++ 98/03

不可能。字符串可以在写入时进行复制,因此需要处理所有读写操作。

C ++一十四分之一十一

在[string.require]中:

  

basic_string对象中类似char的对象应连续存储。也就是说,任何basic_string   对象s&*(s.begin() + n) == &*s.begin() + n的所有值都应保留n 0 <= n < s.size()

因此&str.front()&str[0]应该有效。

C ++ 17

str.data()&str.front()&str[0]工作。

Here它说:

  

charT* data() noexcept;

     

返回:指针pp + i == &operator[](i)中每个i的{​​{1}}。

     

复杂性:恒定时间。

     

要求:程序不得更改存储的值[0, size()]

非const at p + size()正常运作。

recent draft.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()的{​​{1}}类型的对象的引用,其中修改对象会导致未定义的行为。

     

投掷:没什么。

     

复杂性:恒定时间。

所以它使用迭代器算法。所以我们需要检查有关迭代器的信息。 Here它说:

  

3 basic_string是一个连续的容器([container.requirements.general])。

所以我们需要去here

  

连续容器是一个容器,它支持随机访问迭代器([random.access.iterators]),其成员类型charTcharT()是连续的迭代器([iterator.requirements.general])

然后here

  

迭代器进一步满足以下要求:对于整数值n和可解除引用的迭代器值iteratorconst_iteratora等同于(a + n),称为连续迭代器。

显然,连续迭代器是C ++ 17的一项功能,已在these papers中添加。

该要求可以改写为:

*(a + n)

因此,在第二部分中我们取消引用迭代器,然后获取它指向的值的地址,然后对其执行指针算法,取消引用它,它与递增迭代器然后解除引用它相同。这意味着连续的迭代器指向内存,其中每个值都紧接着存储,因此是连续的。由于*(addressof(*a) + n)的函数需要连续的内存,因此您可以将assert(*(a + n) == *(&*a + n)); char*的结果传递给这些函数。

答案 1 :(得分: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添加了非常量data()添加到std::string,但它仍然表示您无法修改缓冲区。

我不知道有任何这样的措辞,因为这会破坏非常规data()的目的,我怀疑这种说法是正确的。

关于

  

现在我计划处理大量信息,复制此缓冲区会产生明显的影响,我想避免它。

如果复制缓冲区有明显的影响,那么您需要避免无意中复制std::string

一种方法是将它包装在一个不可复制的类中。

答案 2 :(得分:0)

我不知道你打算用string做什么,但如果是 你需要的只是一个字符缓冲区,它可以自动释放自己的内存,
然后我通常使用vector<char>vector<int>或任何类型的 您需要的缓冲区。

v为向量,保证&v[0]指向
一个顺序存储器,可以用作缓冲区。