C++17string_view的使用介绍与实现

std::basic_string_view

在标头 <string_view> 定义

template<

    class CharT,
    class Traits = std::char_traits<CharT>

> class basic_string_view;
(C++17 起)

类模板 basic_string_view 描述一个能指代常量连续仿 char 对象序列的对象,序列首元素在零位置。

std::basic_string_view 的每个特化均为可平凡复制 (TriviallyCopyable) 类型。

(C++23 起)

典型的实现仅保有二个成员:指向常 CharT 的指针和大小。

提供数种对常用字符类型的 typedef :

定义于头文件 <string_view>

类型定义
std::string_viewstd::basic_string_view<char>
std::wstring_viewstd::basic_string_view<wchar_t>
std::u8string_view (C++20)std::basic_string_view<char8_t>
std::u16string_viewstd::basic_string_view<char16_t>
std::u32string_viewstd::basic_string_view<char32_t>

模板形参

CharT-字符类型
Traits-指定字符类型上操作的字符特征 (CharTraits) 类。同 basic_string , Traits::char_type 必须指名同 CharT 的类型,否则程序为谬构。

成员类型

成员类型定义
traits_typeTraits
value_typeCharT
pointerCharT*
const_pointerconst CharT*
referenceCharT&
const_referenceconst CharT&
const_iterator实现定义的常老式随机访问迭代器 (LegacyRandomAccessIterator) 常量表达式迭代器 (ConstexprIterator) (C++20 起)兼老式连续迭代器 (LegacyContiguousIterator) ,其 value_type 为 CharT
iteratorconst_iterator
const_reverse_iteratorstd::reverse_iterator<const_iterator>
reverse_iteratorconst_reverse_iterator
size_typestd::size_t
difference_typestd::ptrdiff_t

注解: iterator 与 const_iterator 是同一类型,因为 string_view 是到常字符序列中的视图。

容器 (Container) 的迭代器类型上的所有要求亦应用于 basic_string_view 的 iterator 和 const_iterator 类型。

成员函数

(构造函数)

构造 basic_string_view
(公开成员函数)

operator=

对视图赋值
(公开成员函数)

迭代器

begincbegin

返回指向起始位置的迭代器
(公开成员函数)

endcend

返回指向结尾的迭代器
(公开成员函数)

rbegincrbegin

返回指向起始的反向迭代器
(公开成员函数)

rendcrend

返回指向结尾的反向迭代器
(公开成员函数)

元素访问

operator[]

访问指定字符
(公开成员函数)

at

访问指定字符,带有边界检查
(公开成员函数)

front

访问首个字符
(公开成员函数)

back

访问最末字符
(公开成员函数)

data

返回指向视图首字符的指针
(公开成员函数)

容量

sizelength

返回字符数
(公开成员函数)

max_size

返回最大字符数
(公开成员函数)

empty

检查视图是否为空
(公开成员函数)

修改器

remove_prefix

以后移起点收缩视图
(公开成员函数)

remove_suffix

以前移终点收缩视图
(公开成员函数)

swap

交换内容
(公开成员函数)

操作

copy

复制字符
(公开成员函数)

substr

返回子串
(公开成员函数)

compare

比较二个视图
(公开成员函数)

starts_with

(C++20)

检查 string_view 是否始于给定前缀
(公开成员函数)

ends_with

(C++20)

检查 string_view 是否终于给定后缀
(公开成员函数)

contains

(C++23)

检查字符串视图是否含有给定的子串或字符
(公开成员函数)

find

在视图中查找字符
(公开成员函数)

rfind

寻找子串的最后一次出现
(公开成员函数)

find_first_of

查找字符的首次出现
(公开成员函数)

find_last_of

查找字符的最后一次出现
(公开成员函数)

find_first_not_of

查找字符的首次不出现
(公开成员函数)

find_last_not_of

查找字符的最后一次不出现
(公开成员函数)

常量

npos

[静态]

特殊值。准确含义依赖于语境。
(公开静态成员常量)

非成员函数

operator==operator!=operator<operator>operator<=operator>=operator<=>

(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20 中移除)(C++20)

以字典序比较两个字符串视图
(函数模板)

输入/输出

operator<<

进行字符串视图的流输出
(函数模板)

字面量

定义于内联命名空间 std::literals::string_view_literals

operator""sv

(C++17)

创建一个字符数组字面量的字符串视图
(函数)

 

推导指引(C++20 起)

注解

程序员负责确保 std::string_view 不在被指向数组的生存期外继续生存:

std::string_view good("a string literal");   // OK : "good" 指向静态数组
std::string_view bad("a temporary string"s); // "bad" 保有悬垂指针

即使在 C++23 中引入的正式要求前,所有既存实现中 std::basic_string_view 的特化已经为可平凡复制类型。

使用std::string构造std::string_view

值得一提的是标准并没有规定basic_string_view有对应的构造函数,按照MSVC的实现来说,是basic_string内部实现了一个转换函数可转换到basic_string_view。

代码实现basic_string_view

#ifndef __STRING_VIEW_HPP__
#define __STRING_VIEW_HPP__

#include<iterator>
#include<algorithm>
#include<iostream>
#include<numeric>
#include<string>
#include<type_traits>
#include<memory>

template<typename Traits>
struct _string_view_iterator {
    using value_type        = typename Traits::char_type;
    using difference_type   = ptrdiff_t;
    using pointer           = const value_type*;
    using reference         = const value_type&;

	constexpr reference operator*()const noexcept {
		return *m_ptr;
	}

	constexpr pointer operator->()const noexcept {
		return m_ptr;
	}

	constexpr _string_view_iterator& operator++()noexcept {
		++m_ptr;
		return *this;
	}

	constexpr _string_view_iterator operator++(int)noexcept {
		_string_view_iterator tmp{ *this };
		++* this;
		return tmp;
	}

	constexpr _string_view_iterator& operator--()noexcept {
		--m_ptr;
		return *this;
	}

	constexpr _string_view_iterator operator--(int)noexcept {
		_string_view_iterator tmp{ *this };
		--* this;
		return tmp;
	}

	[[nodiscard]] constexpr _string_view_iterator operator+(size_t n)const noexcept {
		_string_view_iterator tmp{ *this };
		tmp.m_ptr += n;
		return tmp;
	}

	[[nodiscard]] constexpr _string_view_iterator operator-(size_t n)const noexcept {
		_string_view_iterator tmp{ *this };
		tmp.m_ptr -= n;
		return tmp;
	}

	constexpr void operator+=(size_t n) {
		m_ptr += n;
	}

	constexpr void operator-=(size_t n) {
		m_ptr -= n;
	}

	[[nodiscard]] constexpr reference operator[](size_t n) {
		return m_ptr[n];
	}

	friend constexpr bool operator==(const _string_view_iterator& v1, const _string_view_iterator& v2) {
		return v1.m_ptr == v2.m_ptr;
	}

	friend constexpr bool operator<=>(const _string_view_iterator& v1, const _string_view_iterator& v2) {
		if (v1.m_ptr > v2.m_ptr) {
			return 1;
		}
		else if (v1.m_ptr < v2.m_ptr) {
			return -1;
		}
		else {
			return 0;
		}
	}

	friend constexpr size_t operator-(const _string_view_iterator& v1, const _string_view_iterator& v2) {
		return v1.m_ptr - v2.m_ptr;
	}

    pointer m_ptr = nullptr;
};

namespace mylib {
    template<class Elem,class Traits = std::char_traits<Elem>> 
    class basic_string_view {
    public:

        using traits_type            = Traits;
        using value_type             = Elem;
        using pointer                = Elem*;
        using const_pointer          = const Elem*;
        using reference              = Elem&;
        using const_reference        = const Elem&;
        using const_iterator         = _string_view_iterator<Traits>;
        using iterator               = const_iterator;
        using const_reverse_iterator = std::reverse_iterator<const_iterator>;
        using reverse_iterator       = const_reverse_iterator;
        using size_type              = size_t;
        using difference_type        = ptrdiff_t;

		static constexpr auto npos{ static_cast<size_type>(-1) };

        constexpr basic_string_view() noexcept : m_data(nullptr), m_size(0) {}

        constexpr basic_string_view(const basic_string_view&) noexcept = default;

        constexpr basic_string_view(const const_pointer Ntcts) noexcept : m_data(Ntcts), m_size(Traits::length(Ntcts)) {}

        constexpr basic_string_view(const const_pointer Cts, const size_type Count) noexcept : m_data(Cts), m_size(Count) {}

        template <std::contiguous_iterator It, std::sized_sentinel_for<It> Se>
            requires (std::is_same_v<std::iter_value_t<It>, Elem> && !std::is_convertible_v<Se, size_type>)
        constexpr basic_string_view(It First, Se Last) noexcept(noexcept(Last - First)) 
            : m_data(std::to_address(First)), m_size(static_cast<size_type>(Last - First)) {}

		constexpr basic_string_view(const std::string& s) : m_data(s.data()), m_size(s.size()) {}

        constexpr basic_string_view& operator=(const basic_string_view&) noexcept = default;

		constexpr const_iterator begin() const noexcept {
			return { m_data };
		}

		constexpr const_iterator cbegin() const noexcept {
			return  { m_data };
		}

		constexpr const_iterator end() const noexcept {
			return { m_data + m_size };
		}

		constexpr const_iterator cend() const noexcept {
			return { m_data + m_size };
		}

		constexpr const_reverse_iterator rbegin() const noexcept {
			return reverse_iterator(end());
		}
		
		constexpr const_reverse_iterator crbegin() const noexcept {
			return reverse_iterator(end());
		}

		constexpr const_reverse_iterator rend() const noexcept {
			return reverse_iterator(begin());
		}
		
		constexpr const_reverse_iterator crend() const noexcept {
			return reverse_iterator(begin());
		}
		
		constexpr const_reference at(size_type pos) const {
			pos >= size() ? throw  std::out_of_range("out_of_range") : begin()[pos];
		}

		constexpr const_reference operator[](size_type pos) const {
			return begin()[pos];
		}

		constexpr const_reference front() const {
			return *begin();
		}

		constexpr const_reference back() const {
			return *(end() - 1);
		}

		constexpr const_pointer data() const noexcept {
			return m_data;
		}

		constexpr size_type size()const noexcept {
			return m_size;
		}

		constexpr size_type length() const noexcept {
			return m_size;
		}

		constexpr size_type max_size() const noexcept {
			return std::min(static_cast<size_t>(PTRDIFF_MAX), static_cast<size_t>(-1) / sizeof(Elem));
		}

		[[nodiscard]] constexpr bool empty() const noexcept {
			return m_size == 0;
		}

		constexpr void remove_prefix(size_type n) {
			m_data += n;
			m_size -= n;
		}

		constexpr void remove_suffix(size_type n) {
			m_size -= n;
		}

		constexpr void swap(basic_string_view& v) noexcept {
			std::swap(m_data, v.m_data);
			std::swap(m_size, v.m_size);
		}

		constexpr size_type copy(Elem* dest, size_type count, size_type pos = 0) const {
			if (pos > size()) {
				throw std::out_of_range("out_of_range");
			}
			Traits::copy(dest, data() + pos, std::min(count, size() - pos));
			return count;
		}

		constexpr basic_string_view substr(size_type pos = 0, size_type count = npos) const {
			return { m_data + pos, std::min(count, size() - pos) };
		}

		constexpr int compare(basic_string_view v) const noexcept {
			auto ret = Traits::compare(data(), v.data(), std::min(size(), v.size()));
			if (ret < 0) {
				return -1;
			}
			else if (ret == 0) {
				if (size() < v.size()) { return -1; }
				if (size() == v.size()){return 0;}
				if (size() > v.size()) { return 1; }
			}
			else if (ret > 0) {
				return 1;
			}
			return 0;
		}

		constexpr int compare(size_type pos1, size_type count1, basic_string_view v) const {
			return substr(pos1, count1).compare(v);
		}

		constexpr int compare(size_type pos1, size_type count1, basic_string_view v, size_type pos2, size_type count2) const {
			return substr(pos1, count1).compare(v.substr(pos2, count2));
		}

		constexpr int compare(const Elem* s) const {
			return compare(basic_string_view(s));
		}

		constexpr int compare(size_type pos1, size_type count1, const Elem* s) const {
			return substr(pos1, count1).compare(basic_string_view(s));
		}

		constexpr int compare(size_type pos1, size_type count1, const Elem* s, size_type count2) const {
			return substr(pos1, count1).compare(basic_string_view(s, count2));
		}

		constexpr bool starts_with(basic_string_view sv) const noexcept {
			return substr(0, sv.size()) == sv;
		}

		constexpr bool starts_with(Elem c) const noexcept {
			return !empty() && Traits::eq(front(), c);
		}

		constexpr bool starts_with(const Elem* s) const {
			return starts_with(basic_string_view(s));
		}

		constexpr bool ends_with(basic_string_view sv) const noexcept {
			return size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0;
		}

		constexpr bool ends_with(Elem c) const noexcept {
			return !empty() && Traits::eq(back(), c);
		}

		constexpr bool ends_with(const Elem* s) const {
			return ends_with(basic_string_view(s));
		}

		constexpr size_type find(basic_string_view v, size_type pos = 0) const noexcept {
			return std::search(begin() + pos , end(), v.begin(), v.end()) - begin();
		}

		constexpr size_type find(Elem ch, size_type pos = 0) const noexcept {
			return find(basic_string_view(std::addressof(ch), 1), pos);
		}

		constexpr size_type find(const Elem* s, size_type pos, size_type count) const {
			return find(basic_string_view(s, count), pos);
		}

		constexpr size_type find(const Elem* s, size_type pos = 0) const {
			return find(basic_string_view(s), pos);
		}
		
		constexpr size_type rfind(basic_string_view v, size_type pos = 0) const noexcept {
			return std::find_end(begin() + pos, end(), v.begin(), v.end()) - begin();
		}

		constexpr size_type rfind(Elem ch, size_type pos = 0) const noexcept {
			return rfind(basic_string_view(std::addressof(ch), 1), pos);
		}

		constexpr size_type rfind(const Elem* s, size_type pos, size_type count) const {
			return rfind(basic_string_view(s, count), pos);
		}

		constexpr size_type rfind(const Elem* s, size_type pos = 0) const {
			return rfind(basic_string_view(s), pos);
		}

		constexpr size_type find_first_of(basic_string_view v, size_type pos = 0) const noexcept {
			for (const auto& i : v) {
				auto t = std::find(begin() + pos , end(), i);
				if (t != end()) {
					return t - begin();
				}
			}
			return pos;
		}
	
		constexpr size_type find_first_of(Elem c, size_type pos = 0) const noexcept {
			return find_first_of(basic_string_view(std::addressof(c), 1), pos);
		}
	
		constexpr size_type find_first_of(const Elem* s, size_type pos, size_type count) const {
			return find_first_of(basic_string_view(s, count), pos);
		}
	
		constexpr size_type find_first_of(const Elem* s, size_type pos = 0) const {
			return find_first_of(basic_string_view(s), pos);
		}

		constexpr size_type find_last_of(basic_string_view v, size_type pos = npos) const noexcept {
			size_type ret{};
			for (const auto& i : v) {
				auto t = std::find(begin() + pos, end(), i);
				if (t != end()) {
					ret = t - begin();
				}
			}
			return ret != 0 ? ret : pos;
		}
		
		constexpr size_type find_last_of(Elem c, size_type pos = npos) const noexcept {
			return find_last_of(basic_string_view(std::addressof(c), 1), pos);
		}
		
		constexpr size_type find_last_of(const Elem* s, size_type pos, size_type count) const {
			return find_last_of(basic_string_view(s, count), pos);
		}
		
		constexpr size_type find_last_of(const Elem* s, size_type pos = npos) const {
			return find_last_of(basic_string_view(s), pos);
		}

		constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0) const noexcept {
			for (const auto& i : v) {
				auto t = std::find(begin() + pos , end(), i);
				if (t == end()) {
					return  t - begin();
				}
			}
			return npos;
		}

		constexpr size_type find_first_not_of(Elem c, size_type pos = 0) const noexcept {
			return find_first_not_of(basic_string_view(c), pos);
		}

		constexpr size_type find_first_not_of(const Elem* s, size_type pos, size_type count) const {
			return find_first_not_of(basic_string_view(s, count), pos);
		}

		constexpr size_type find_first_not_of(const Elem* s, size_type pos = 0) const noexcept {
			return find_first_not_of(basic_string_view(s), pos);
		}

		constexpr size_type find_last_not_of(basic_string_view v, size_type pos = npos) const noexcept {
			size_type ret{};
			for (const auto& i : v) {
				auto t = std::find(begin() + pos , end(), i);
				if (t == end()) {
					ret =  t - begin();
				}
			}
			return ret != 0 ? ret : pos;
		}
		
		constexpr size_type find_last_not_of(Elem c, size_type pos = npos) const noexcept {
			return find_last_not_of(basic_string_view(std::addressof(c), 1), pos);
		}
		
		constexpr size_type find_last_not_of(const Elem* s, size_type pos, size_type count) const {
			return find_last_not_of(basic_string_view(s, count), pos);
		}
		
		constexpr size_type find_last_not_of(const Elem* s, size_type pos = npos) const {
			return find_last_not_of(basic_string_view(s), pos);
		}
		
    private:
		
        const_pointer m_data;
        size_type m_size;
    };
    
	using string_view    = mylib::basic_string_view<char>;
	using wstring_view   = mylib::basic_string_view<wchar_t>;
	using u8string_view  = mylib::basic_string_view<char8_t>;
	using u16string_view = mylib::basic_string_view<char16_t>;
	using u32string_view = mylib::basic_string_view<char32_t>;

	template< class CharT, class Traits >
	constexpr bool operator==(mylib::basic_string_view<CharT, Traits> lhs,mylib::basic_string_view<CharT, Traits> rhs) noexcept {
		return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
	}

	template< class CharT, class Traits >
	constexpr auto operator<=>(mylib::basic_string_view<CharT, Traits> lhs, mylib::basic_string_view<CharT, Traits> rhs) noexcept {
		return lhs.compare(rhs);
	}

	template<typename T>
	std::ostream& operator<<(std::ostream& out, const mylib::basic_string_view<T>& v) {
		for (const auto& i : v) {
			std::cout << i;
		}
		return out;
	}

	constexpr string_view operator "" _sv(const char* str, std::size_t len) noexcept {
		return { str,len };
	}		  
			  
	constexpr u8string_view operator "" _sv(const char8_t* str, std::size_t len) noexcept {
		return { str,len };
	}		  
			  
	constexpr u16string_view operator "" _sv(const char16_t* str, std::size_t len) noexcept {
		return { str,len };
	}		  
			  
	constexpr u32string_view operator "" _sv(const char32_t* str, std::size_t len) noexcept {
		return { str,len };
	}		  
			  
	constexpr wstring_view operator "" _sv(const wchar_t* str, std::size_t len) noexcept {
		return { str,len };
	}

	template<class It, class End>
	basic_string_view(It, End)->basic_string_view<std::iter_value_t<It>>;

}

#endif

std::basic_string_view - cppreference.comhttps://zh.cppreference.com/w/cpp/string/basic_string_view

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
string_viewstring都是C++ STL中的字符串类型,但它们有着不同的特点和用途。 stringC++中常用的字符串类型,它是一个可变长的字符串容器,可以动态增加或删除字符。它存储的字符串是一个连续的字符数组,可以通过下标或迭代器进行访问和修改。string支持很多字符串操作,如查找、替换、插入、删除、子串等。 string_viewC++17新增的类型,它是一个不可变的字符串视图。它本质上是一个只包含指向原始字符串的指针和长度信息的结构体,它不拥有原始字符串的内存空间,也不会对原始字符串进行修改。它主要用于读取和处理字符串,可以提高程序的效率和安全性。string_view可以用于任何可以转换为const char*的类型,如string、字符数组、字面量等。 下面是string_viewstring的区别和联系: 1. 内存管理方式不同:string拥有自己的内存空间,而string_view不拥有内存空间,只是指向原始字符串的一个视图。 2. 可变性不同:string是可变的,可以修改字符串内容;而string_view是不可变的,只能读取字符串内容。 3. 使用场景不同:string_view主要用于只读操作,可以提高程序效率和安全性,特别是在处理大量字符串时。而string则适用于需要频繁修改字符串的场景。 4. 接口相似:string_viewstring都支持类似的操作,如查找、比较、子串等。 总之,string_viewstring都是C++中常用的字符串类型,它们各有优点和适用场景。在实际编程中,可以根据需要选择合适的字符串类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值