C++17 string_view避免分配

string_view 是C++17所提供的用于处理只读字符串的轻量对象。这里后缀 view 的意思是只读的视图。

  1. 通过调用 string_view 构造器可将字符串转换为 string_view 对象。
    string 可隐式转换为 string_view。
  2. string_view 是只读的轻量对象,它对所指向的字符串没有所有权。
  3. string_view通常用于函数参数类型,可用来取代 const char* 和 const string&。
  4. string_view 代替 const string&,可以避免不必要的内存分配。
  5. string_view的成员函数即对外接口与 string 相类似,但只包含读取字符串内容的部分。string_view::substr()的返回值类型是string_view,不产生新的字符串,不会进行内存分配。string::substr()的返回值类型是string,产生新的字符串,会进行内存分配。
  6. string_view字面量的后缀是 sv。(string字面量的后缀是 s)。

使用 std::string_view 可以避免字符串数据的复制,从而提高程序效率。C++ 中的 string 类型在堆上存放自己的字符串数据,所以当你处理 string 类型的时候,很容易就会产生(堆)内存分配。在实际应用中,字符串操作会很频繁,频繁的内存分配会拖慢程序的运行速度。

示例代码:

  1. NO string_view
#include <iostream>
#include <string>
#include <string_view>

static uint32_t s_AllocCount = 0;

//操作符重载跟踪内存分配次数和分配大小
void* operator new(size_t size)
{
	s_AllocCount++;
	std::cout << "Allocating " << size << " bytes" << std::endl;
	return malloc(size);
}


//std::string和c++17 std::string_view比较
//#define start_view 1
#if start_view
void PrintName(std::string_view name)
{
	std::cout << name << std::endl;
}
#else
void PrintName(const std::string& name)
{
	std::cout << name << std::endl;
}
#endif


int main()
{
	std::string name = "Hello world";
	
#if start_view
	std::string_view fistName(name.c_str(), 5);
	std::string_view lastName(name.c_str() + 6, 5);
#else
	std::string fistName = name.substr(0, 5);
	std::string lastName = name.substr(6, 10);
#endif

	PrintName(name);
	PrintName(fistName);
	PrintName(lastName);

	std::cout << s_AllocCount << " allocations" << std::endl;
	std::cin.get();
}

使用一个简单得PrintName函数分别打印整个name和第一个单词和第二个单词,在没有使用string_view时,运行结果:

Allocating 8 bytes
Allocating 8 bytes
Allocating 8 bytes
Hello world
Hello
world
3 allocations

这里打印了三次进行了三次内存分配,那么1000次,10000次,则会严重影响程序运行效率。

  1. string_view
#include <iostream>
#include <string>
#include <string_view>

static uint32_t s_AllocCount = 0;

//操作符重载跟踪内存分配次数和分配大小
void* operator new(size_t size)
{
	s_AllocCount++;
	std::cout << "Allocating " << size << " bytes" << std::endl;
	return malloc(size);
}


//std::string和c++17 std::string_view比较
#define start_view 1
#if start_view
void PrintName(std::string_view name)
{
	std::cout << name << std::endl;
}
#else
void PrintName(const std::string& name)
{
	std::cout << name << std::endl;
}
#endif


int main()
{
	std::string name = "Hello world";
	
#if start_view
	std::string_view fistName(name.c_str(), 5);
	std::string_view lastName(name.c_str() + 6, 5);
#else
	std::string fistName = name.substr(0, 5);
	std::string lastName = name.substr(6, 10);
#endif

	PrintName(name);
	PrintName(fistName);
	PrintName(lastName);

	std::cout << s_AllocCount << " allocations" << std::endl;
	std::cin.get();
}

输出结果:

Allocating 8 bytes
Hello world
Hello
world
1 allocations

在这里仅仅经行了一次内存分配,发生在std::string name = "Hello world";

实际上在不同的编译器中结果似乎是不同的,在gcc中打出如上代码后并没有获得一样的结果,在gcc中PrintName函数中的引用并没有向堆申请内存,而vc编译器却向堆申请了内存。
这是因为:gcc的string默认大小是32个字节,字符串小于等于15直接保存在栈上,超过之后才会使用new分配。

额外的

让std:string 更快的方法是不用它,std::string name = "Hello world";name是一个静态字符串,可以直接使用const char* name = "Hello world",然后修改

std::string_view fistName(name.c_str(), 5);
std::string_view lastName(name.c_str() + 6, 5);

std::string_view fistName(name, 5);
std::string_view lastName(name + 6, 5);

可以得到0分配。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值