首页 > 编程语言 >C++面试八股文:std::string是如何实现的?

C++面试八股文:std::string是如何实现的?

时间:2023-06-24 23:55:33浏览次数:60  
标签:std 面试官 capacity string C++ 字符串 size

C++面试八股文:std::string是如何实现的?

某日二师兄参加XXX科技公司的C++工程师开发岗位第18面:

面试官:std::string用过吧?

二师兄:当然用过(废话,C++程序员就没有没用过std::string的)。

面试官:std::string("hello")+"world""hello"+std::string("world")std::string("hello")+std::string("world")的结果是什么?为什么?

二师兄:前者和后者的结果都是std::string的对象,内容是“helloworld\0”,而中间的这个表达式无法通过编译。原因是std::string重载了operator+(const char*)operator+(const std::string&),但是const char* 却没有重载operator+运算符。

面试官:std::string 有两个APIresizereserve,你知道它们之间的区别吗?

二师兄:resize对应的是sizeresize可以改变字符串的大小。reserve对应的是capacityreserve只能改变capacity的大小。

二师兄:当resize传入的参数小于字符串的szie时,多余的字符串会被截取。当reserve传入的参数小于capacity时,reserve什么也不会做。

二师兄:当resize传入的参数大于字符串的szie时,增加的字符串会被默认初始化。当reserve传入的参数大于capacity时,capacity会被扩容。

面试官:好的。可以通过下标访问std::string实例的内容吗?

二师兄:可以的,std::string重载了下标运算符,可以像数组一样通过下标运算取出某个字符。

面试官:你知道std::stringat成员方法吗?

二师兄: 嗯,和下标运算功能相似,不过不用担心越界问题。可以安全的访问字符串中的字符。

面试官:既然有at方法了,为什么还要重载下标运算符呢?

二师兄:主要是因为性能上的考量。at虽然保证了不会超出字符串范围(超出范围抛出异常),但是性能低于下标操作。这就是有舍有得。为了安全使用at,为了性能使用下标操作。C++给了你多个选择,如何选择看你的需求。

面试官:那你知道std::string是如何实现的吗?

二师兄:在string内部维护一个指针,这个指针指向真正的字符串的位置。

面试官:能简单的写一下实现代码吗?

二师兄:好的。

class string
{
public: 
    string():size_(0),data_(nullptr){}
    explicit string(const char* c)
    {
        size_ = strlen(c);
        data_ = (char*)malloc(size_+1);
        memset(data_,0,size_+1);
        memcpy(data_,c,size_);
    }
    size_t size() const {return size_;}
	const char* c_str() const {return data_;}
private:
    size_t size_;
    char* data_;
};

二师兄:在实现append或者+=的时候,需要把当前字符的长度加上append的内容的长度,以此长度申请一块新内存,然后把当前字符串的内存和append 的内容考入新申请的内存中。free掉之前data_指向的内存,然后把data_指针指向新申请的内存。

面试官:好的。这样的实现有一些弊端。如果频繁的对一个std::string对象append内容,会发生什么?

二师兄:是的,因为频繁的mallocfree,会有性能问题。因所以编译器在实现std::string的时候一般会预先申请一块大的内存,这块内存的长度是capacity,当添加的字符串的长度加上当前的字符串长度小于capacity时,直接添加到当前的块上即可。

面试官:好的。针对字符串比较少的情况,一般编译器会做一些优化,你知道如何优化的吗?

二师兄:这个好像在哪看过,不记得额。。。

面试官:好的,今天的面试结束了,请回去等通知吧。

今天二师兄的表现不错,除了最后一个问题,基本上都答上来了。让我们来看下这个问题:

针对字符串比较少的情况,一般编译器会做一些优化,你知道如何优化的吗?

我们可以看看GCC中std::string的实现:

typedef basic_string<char> string;

_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;
};

这里的_CharT就是char,所以_S_local_capacity等于15。当字符串的长度小于等于15时,直接存在_M_local_buf中,而不需要在堆中申请内存。当字符串长度大于15时,在内存中申请一块内存,这块内存的起始地址保存在_M_dataplus中,这块内存的容量保存在_M_allocated_capacity 中,而字符串的真实长度保存在_M_string_length中。当向字符串中添加字符时,如果添加字符的长度大于 _M_allocated_capacity - _M_string_length,则需要resize,否则直接追加到_M_dataplus保存的内存块中即可。

标签:std,面试官,capacity,string,C++,字符串,size
From: https://www.cnblogs.com/bujidao1128/p/17501900.html

相关文章

  • Qt/c++类型转换总结
    1、static_cast、dynamic_cast、强制转换(reinterpret_cast和const_cast)、qobject_cast、qstatic_cast以及qdynamic_cast的区别:static_cast:用于执行静态类型转换,可以进行常见的类型转换,例如基本类型之间的转换、向上转型、向下转型(但没有运行时类型检查)等。在C++中......
  • C/C++ 类型显式转换
    上一章,我提到了下面的代码#include<stdio.h>inta=(long)4;externchark=(int)'m';voidmain(void){printf("%s",a);printf("%f",k);}这里我需要纠正上一篇文章的错误,C语言不存在bool类型只要数字是大于0,那么相当于true否则就是false 其中,inta表示......
  • C++面试八股文:std::vector和std::list,如何选择?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第24面:面试官:list用过吗?二师兄:嗯,用过。面试官:请讲一下list的实现原理。二师兄:std::list被称为双向链表,和C中手写双向链表本质上没有大的区别。list对象中有两个指针,一个指向上一个节点(node),一个指向下一个节点(node)。二师兄:与手写......
  • string类(一)
    string类对象的常见构造string类实现了多个构造函数的重载,常用的构造函数如下:(constructor)函数名称功能说明string()构造空的string类对象,即空字符串string(constchars)*用C-string来构造string类对象string(constchar*s,size_tn)复制s所指字符序列......
  • C++面试八股文:std::vector和std::list,如何选择?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第24面:面试官:list用过吗?二师兄:嗯,用过。面试官:请讲一下list的实现原理。二师兄:std::list被称为双向链表,和C中手写双向链表本质上没有大的区别。list对象中有两个指针,一个指向上一个节点(node),一个指向下一个节点(node)。二师兄:与手......
  • [QML]从零开始QML开发(二)QML开发,浅谈控件、槽函数、锚等基本概念。QML和C++怎么交互?贯
    [QML]从零开始QML开发(二)QML开发,浅谈控件、槽函数、锚等基本概念。QML和C++怎么交互?贯彻落实MVC原则先看代码:importQtQuick2.12importQtQuick.Window2.12importQtQuick.Controls2.5Window{visible:truewidth:320height:480title:qsTr("HelloW......
  • C++ 核心指南之资源管理(上)
    C++核心指南(C++CoreGuidelines)是由BjarneStroustrup、HerbSutter等顶尖C++专家创建的一份C++指南、规则及最佳实践。旨在帮助大家正确、高效地使用“现代C++”。这份指南侧重于接口、资源管理、内存管理、并发等High-level主题。遵循这些规则可以最大程度地保证静......
  • redis-string常用命令
    string类型的常用命令常用SET/GET SETk1v1 EX参数:以秒为单位设置过期时间setk2v2EX10PX参数:以毫秒为单位设置过期时间setk2v2PX10000EXAT参数:设置以秒为单位的UNIX时间戳所对应的时间为过期时间PXAT参数:设置以毫秒为单位的UNIX时间戳所对应的时间为过期时......
  • Book-Effective C++ 改善程序与设计的55个具体做法
    Book-EffectiveC++改善程序与设计的55个具体做法让自己习惯C++AccustomingYourselftoC++条款01:视C++为一个语言联邦/ViewC++asafederationoflanguages.条款02:尽量以const,enum,inline替换#define/Preferconsts,enums,andinlinesto#defines.条款0......
  • [C/C++] Visual Stdio Code中多线程多源码文件编译、运行和调试
    搞了很久,记录一下:一.环境OS:Ubuntu20.04VSCode:1.77.0g++:g++(Ubuntu9.4.0-1ubuntu1~20.04.1)9.4.0二.配置文件下面两个文件先不要手动创建,下面第三章会讲到:task.json:编译程序的配置文件;launch.json:运行程序的配置文件.三.编译&运行1.打开main函数所在的cpp文......