IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> g++ std标准库对std::string的实现分析 -> 正文阅读

[C++知识库]g++ std标准库对std::string的实现分析

不同编译器对C++标准库的实现都有各自的逻辑和风格,对于字符串类型,gnu c++

template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string {
  struct _Alloc_hider : allocator_type  // TODO check __is_final
  {
    _Alloc_hider(pointer __dat, const _Alloc &__a)
        : allocator_type(__a), _M_p(__dat) {}

    _Alloc_hider(pointer __dat, _Alloc &&__a = _Alloc())
        : allocator_type(std::move(__a)), _M_p(__dat) {}

    pointer _M_p;  // The actual data.
  };

  _Alloc_hider _M_dataplus;
  size_type _M_string_length;

  enum { _S_local_capacity = 15 / sizeof(_CharT) };

  union {
    _CharT _M_local_buf[_S_local_capacity + 1];
    size_type _M_allocated_capacity;
  };
};
_Alloc_hider _M_dataplus;     // 指向真实数据的指针
size_type _M_string_length;   // 字符串长度
union {
  _CharT _M_local_buf[_S_local_capacity + 1];
  size_type _M_allocated_capacity;
};							  // 联合体:存储栈上开辟的存放字符数组,或者保存堆上开辟字符数组大小

gnu c++制定string的方法中,常会判断字符串当前保存在不在栈上,具体方式通过:

// 返回堆上开辟内存首地址
pointer _M_data() const { return _M_dataplus._M_p; }

// 返回栈上数组首地址
const_pointer _M_local_data() const {
#if __cplusplus >= 201103L
	return std::pointer_traits<const_pointer>::pointer_to(*_M_local_buf);
#else
	return const_pointer(_M_local_buf);
#endif
}

// 比较地址是否相等,相等则表示字符串在栈上
bool _M_is_local() const { return _M_data() == _M_local_data(); }

当string长度小于等于_S_local_capacity时,将每个字符存在_M_local_buf指向的栈上。 当string长度大于_S_local_capacity时,在堆上分配。

string和vector很像,他的capacity方法返回值均为预占空间大小

size_type capacity() const _GLIBCXX_NOEXCEPT {
	return _M_is_local() ? size_type(_S_local_capacity) : _M_allocated_capacity;
}

从源码可以看到,首先判断字符串当前保存在不在栈上,是则返回_S_local_capacity,不是则返回堆上开辟的字符串大小,他们均不包含尾部\0

另外C++11后涉及到移动,可以预料到栈上15个字节是通过数组拷贝,而大于15字节后,将内存移入堆上,堆上的移动,就是指针的交换了。

basic_string(basic_string&& __str) noexcept
    : _M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) {
  if (__str._M_is_local()) {
    traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1);
  } else {
    _M_data(__str._M_data());
    _M_capacity(__str._M_allocated_capacity);
  }

  // Must use _M_length() here not _M_set_length() because
  // basic_stringbuf relies on writing into unallocated capacity so
  // we mess up the contents if we put a '\0' in the string.
  _M_length(__str.length());
  __str._M_data(__str._M_local_data());
  __str._M_set_length(0);
}

短字符使用栈内存存放的优势得益于栈的快捷,在性能上略高于操作堆上数据。

之所以单独讨论gun c++,因为它相对于msvc对于短字符的处理是不同的,在msvc中,即使是短字符,也是申请在堆上,除此以外几乎相同。
可使用一下方式,在linux和windows上面分别使用g++或者llvm,对比msvc的输出结果,需要指出一定要编译器支持或者打开C++11

#include <cstdio>
#include <cstdlib>
#include <new>
#include <string>

std::size_t allocated = 0;

void* operator new(size_t sz) {
  void* p = std::malloc(sz);
  allocated += sz;
  return p;
}

void operator delete(void* p) noexcept { return std::free(p); }

auto main() -> int {
  allocated = 0;
  std::string s("11111111111111111");  // 改变字符串长度,以15为界
  std::printf(
      "stack space = %zu, heap space = %zu, capacity = %zu, size = %zu\n",
      sizeof(s), allocated, s.capacity(), s.size());

  std::string ss;
  ss.swap(s);
  std::printf(
      "stack space = %zu, heap space = %zu, capacity = %zu, size = %zu\n",
      sizeof(s), allocated, s.capacity(), s.size());
}

参考:知乎

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-28 22:43:27  更:2021-12-28 22:43:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:55:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码