【问题标题】:Does a std::string always require heap memory?std::string 是否总是需要堆内存?
【发布时间】:2017-02-15 05:16:23
【问题描述】:

我有一个简单的问题。我想知道std::string在C++中是否每次都分配内存。

在我的代码中,构造函数似乎将使用更多的内存来构造tst_first_string,而不是tst_second_string

 char* first_string = new char[5];
 strcpy(first_string, "test");
 std::string tst_first_string(first_string);
 std::string tst_second_string("test");

【问题讨论】:

标签: c++ memory stdstring


【解决方案1】:

字符串文字是只读的。因此,一个可能的优化是,当 std::string 指向一个文字时,它仅包含一个 char * 加上一个标志,表明这就是它所代表的内容。当您写入时,它当然必须分配内存。

【讨论】:

  • 虽然我相信这样的优化在技术上是合法的(你不能编写一个有效的 C++ 程序来判断它是否存在),但我很确定没有编译器/库(两者都会必须合作),实现这样的优化。
  • 他们需要合作,但不是深度合作。字符串文字与堆栈、堆或(通常)可写的全局变量位于不同的内存区域。并不是说我曾经实现过 std::string。 throw 语义可能存在问题(str[0] = 'x' 是否允许为 no throw?)。
  • @MalcolmMcLean:std::string 不允许写入时复制,因此您不能只指向字符串文字并跟踪它是否需要复制。
  • 不允许的是 std::string one = something;标准:;字符串二 = 一;二是写时复制。不懒惰地持有字符串文字。 (特别是如果 std:;string 永远不会被 const 取消限定)。
  • 其实是禁止的,因为noexcept和对各个成员的性能保证,和一般的COW一样。
【解决方案2】:

tst_first_stringtst_second_string 都将使用const char* 的构造函数来构造。由于在这两种情况下,nul 终止符之前 的字符数是相同的,因此您想象 构造将完全相同。也就是说,C++ 标准故意模糊了关于内存管理必须发生的事情,因此您不会绝对确定。

还请注意,许多std::string 实现利用短字符串优化技术来处理小字符串,这会导致整个对象以自动存储持续时间写入内存。在您的情况下,可能根本不使用动态内存。

我们确实知道,从 C++11 开始,std::string 的写时复制语义不再被允许,因此将创建两个不同的字符串

【讨论】:

  • 这也取决于分配器。可以使用基于堆栈的分配器,因此在这种情况下无论如何都不会涉及堆。
  • @vsoftco 如果你改变分配器,它就不再是std::string了。
  • 好吧,我们也不应该忽视 as-if 规则,以及省略/合并一些更动态的分配的额外明确要求。
【解决方案3】:

这是实现定义的,但作为示例,如果字符串的长度小于 16 个字节,Visual C++ 2015 Update 3 上的 std::basic_string 实现将使用内部数组。这是来自<xstring>_String_val 的大量编辑部分:

template<class _Val_types>
class _String_val
{
public:
    typedef typename _Val_types::value_type value_type;

    enum
    {   // length of internal buffer, [1, 16]
        _BUF_SIZE = 16 / sizeof (value_type) < 1 ? 1
            : 16 / sizeof (value_type)
    };

    value_type *_Myptr()
    {   // determine current pointer to buffer for mutable string
        return (this->_BUF_SIZE <= _Myres
            ? _Bx._Ptr
            : _Bx._Buf);
    }

    union _Bxty
    {   // storage for small buffer or pointer to larger one
        value_type _Buf[_BUF_SIZE];
        pointer _Ptr;
    } _Bx;
};

如果您查看_Myptr(),您会注意到当长度小于_BUF_SIZE 时使用_Buf,否则使用_Ptr

不用说,除了标准库的这个特定实现之外,您不应该依赖于其他任何事情。这是一个随时可能改变的内部细节。

【讨论】:

    【解决方案4】:

    这取决于字符串的实现和长度。

    大多数主要实现都有短字符串优化 (SSO),其中字符串存储在字符串对象本身中。

    【讨论】:

      猜你喜欢
      • 2016-01-12
      • 2020-09-01
      • 1970-01-01
      • 2013-03-08
      • 1970-01-01
      • 1970-01-01
      • 2018-02-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多