标准是否保证string :: erase和string :: pop_back不重新分配内存?

时间:2017-08-29 08:32:46

标签: c++ string

标准是否保证string::erasestring::pop_back DO NOT 重新分配内存?擦除一些元素后,string可能会自动缩小吗?

我检查了标准,它说string::erasestring::pop_back要么抛出std::out_of_range要么投掷任何东西。我是否可以将此作为这些方法 NOT 进行重新分配的保证?由于重新分配可能会抛出bad_alloc

4 个答案:

答案 0 :(得分:3)

不,合理的实现可能不会重新分配,但标准并不能保证这些方法调用不会重新分配,标准会说明要求:

  

引用a的元素的引用,指针和迭代器   basic_­string序列可能会因以下用途而失效   那个basic_string对象:

     

(4.1)   作为任何标准库函数的参数,将非const basic_string作为参数引用.227

     

(4.2)   调用非const成员函数,除了operator [],at,data,front,back,begin,rbegin,end和rend

两种提议的方法属于第2类,因此两者都可能会改变capacity(),这隐含意味着重新分配。

pop_back必须与erase具有相同的效果,因为erase被指定为:

  

效果:确定字符串的有效长度xlen   已删除nsize() - pos中的较小者。 3

     

然后,该函数将*this控制的字符串替换为长度为size() - xlen的字符串,其第一个pos元素是   由*this控制的原始字符串的初始元素,和   其余元素是原始元素的副本   由位置*this开始的pos + xlen控制的字符串。

无法保证如何制作副本,因此可以进行额外分配或重新分配。

至于

  

我是否可以将此视为这些方法不做任何保证的保证   重新分配?由于重新分配可能会抛出bad_alloc

该标准似乎没有明确提及由任何方法引起的bad_alloc的可能性。即使绑定了reserve,也没有提及它:

  

void reserve(size_type res_arg=0);

     

投掷:length_­error res_­arg > max_­size()

因此我认为不能做出这样的假设。

答案 1 :(得分:2)

是的,您可以假设这些函数上的投掷:禁止重新分配(可能会抛出bad_alloc)。

20.5.5.12异常处理的限制[res.on.exception.handling]

  

C ++标准库中定义的任何函数都可以报告   通过抛出中引用的类型的异常抛出失败:   段落,或从中命名的类型派生的类型:   将被基数的异常处理程序捕获的段落   类型。

...

  

C ++标准库中定义的没有的函数   抛出:段落,但确实有一个潜在抛出的异常规范可能抛出实现定义   例外。 186 实现应报告错误   抛出标准异常类的异常或派生   (21.6.3.1,21.8,22.2)。

请注意,规范没有明确说明标有" 的内容:没有。"不能扔任何东西。但在某些时候,常识必须接管。该标准也没有明确说明这些功能无法重新格式化您的磁盘。一般来说,标准规定了可以做的功能,并且不允许他们做任何其他。

函数抛出未在抛出:规范(或派生类型)中列出的异常的唯一方法是客户端以调用未定义行为的方式使用它。

答案 2 :(得分:1)

阅读documentation,我认为这取决于函数的签名。在basic_string& erase(size_type pos = 0, size_type n = npos);的情况下,它被描述为前一个字符串的副本。在iterator erase(const_iterator first, const_iterator last);的情况下,元素已删除

实际上我对这种差异感到非常惊讶。我想你不能确定没有分配。

编辑请注意,在这个小例子中,我在每次检查时保留相同的地址:

#include <iostream>
int main()
{
    std::string a;
    for(std::size_t i = 0; i < 10000; ++i)
        a += "Hello World ! My name is Bond... James Bond.";
    std::cout << (long)&a[0] << std::endl;
    a.erase(400000);
    std::cout << (long)&(a[0]) << std::endl;
    a.erase(10);
    std::cout << (long)&(a[0]) << std::endl;
    return 0;
}

答案 3 :(得分:1)

我认为这是有保证的,即使标准也没有明确说明。以下是关于reallocationshrink_to_fit的影响的说明:

  

备注:重新分配使引用序列中元素的所有引用,指针和迭代器以及过去的迭代器无效。如果没有重新分配,它们仍然有效。

如果重新分配发生,所有迭代器,指针,引用都将失效。但是erasepop_back没有提到这一点;这意味着它们不会导致所有这些都失效,然后重新分配就不会发生。