百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

c++ 疑难杂症(11) std::forward_list

liebian365 2024-11-18 14:22 26 浏览 0 评论

c++ 11 链表容器新增加了std::forward_list, 它与std::list有什么不同, 学习学习。

std::forward_list - cppreference.com

1. 定义

std::forward_list 是支持从容器中的任何位置快速插入和移除元素的容器。不支持快速随机访问。它实现为单链表,且实质上与其在 C 中的实现相比无任何开销。与 std::list 相比,此容器在不需要双向迭代时提供更好的存储空间效率。

在链表内或跨数个链表添加、移除和移动元素,不会使当前指代链表中其他元素的迭代器失效。然而,在从链表移除元素(通过 erase_after)时,指代对应元素的迭代器或引用会失效。

std::forward_list 满足容器 (Container) (但不包括 size 成员函数,且 operator== 的复杂度始终为线性)、知分配器容器 (AllocatorAwareContainer) 和序列容器 (SequenceContainer) 的要求。

成员类型

成员类型

定义

value_type

T

allocator_type

Allocator

size_type

无符号整数类型(通常是 std::size_t)

difference_type

有符号整数类型(通常是 std::ptrdiff_t)

reference

value_type&

const_reference

const value_type&

pointer

std::allocator_traits<Allocator>::pointer

const_pointer

std::allocator_traits<Allocator>::const_pointer

iterator

指向 value_type 的常老式向前迭代器 (LegacyForwardIterator)

const_iterator

指向 const value_type 的老式向前迭代器 (LegacyForwardIterator)

成员函数

(构造函数)

构造 forward_list (公开成员函数)

(析构函数)

析构 forward_list (公开成员函数)

operator=

赋值给容器 (公开成员函数)

assign

将值赋给容器 (公开成员函数)

assign_range

(C++23)

将一个范围的值赋给容器 (公开成员函数)

get_allocator

返回关联的分配器 (公开成员函数)

元素访问


front

访问第一个元素 (公开成员函数)

迭代器


before_begin

cbefore_begin

返回指向容器开头之前的迭代器 (公开成员函数)

begin cbegin

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

end cend

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

容量


empty

检查容器是否为空 (公开成员函数)

max_size

返回可容纳的最大元素数 (公开成员函数)

修改器


clear

清除内容 (公开成员函数)

insert_after

在某个元素后插入新元素 (公开成员函数)

emplace_after

在元素后原位构造元素 (公开成员函数)

insert_range_after

(C++23)

插入元素范围到元素后 (公开成员函数)

erase_after

擦除元素后的元素 (公开成员函数)

push_front

插入元素到容器起始 (公开成员函数)

emplace_front

在容器头部原位构造元素 (公开成员函数)

prepend_range

(C++23)

添加元素的范围到起始 (公开成员函数)

pop_front

移除首元素 (公开成员函数)

resize

改变存储元素的个数 (公开成员函数)

swap

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

操作


merge

合并两个有序列表 (公开成员函数)

splice_after

从另一 forward_list 移动元素 (公开成员函数)

remove

remove_if

移除满足特定标准的元素 (公开成员函数)

reverse

反转元素的顺序 (公开成员函数)

unique

删除连续的重复元素 (公开成员函数)

sort

对元素进行排序 (公开成员函数)

2. 示例

  • 初始化
#include <iostream>
#include <forward_list>

int main() {
    
    auto show = [](const char* str, const std::forward_list<int>& f) {
        std::cout <<str<< " : ";
        for (const auto& v : f) {
            std::cout << v << " ";
        }
        std::cout << std::endl;
    };

    std::forward_list<int> f1{1, 2, 3, 4, 5};
    show("f1", f1);
    std::forward_list<int> f2(f1);
    show("f2", f2);
    std::forward_list<int> f3 = f1;
    show("f3", f3);
    std::forward_list<int> f4;
    f4.assign(f1.begin(), f1.end());
    show("f4", f4);
    std::forward_list<int> f5;
    f5.assign({ 1, 2, 3, 4, 5 });
    show("f5", f5);
    std::forward_list<int> f6;
    f6.assign(5, 0);
    show("f6", f6);
    return 0;
}
  • 迭代器
#include <iostream>
#include <forward_list>
#include <algorithm> 

int main() {
    
    std::forward_list<int> f1{1, 2, 3, 4, 5};
    {
        auto iter = f1.begin();
        iter++;
        //iter--; 错误
        //如名字所示, 只能向进,不能后退
    }

    //注意: 返回指向容器开头之前的迭代器
    //就是出现一个空的项, 在首项之前.
    for (auto iter = f1.before_begin(); iter != f1.end(); ++iter) {
        if (iter == f1.before_begin()) {
            //应处理一些初始化动作
            std::cout << "before_begin : ";
            continue;
        }
        std::cout << *iter << " ";
    }
    std::cout << std::endl;
    //打印输出 : 0 1 2 3 4 5

    //std::forward_list<int>::iterator
    for (auto iter = f1.begin(); iter != f1.end(); ++iter) {
        std::cout << *iter << " ";
    }
    std::cout << std::endl;

    //std::forward_list<int>::const_iterator iter
    for (auto iter = f1.cbegin(); iter != f1.cend(); ++iter) {
        std::cout << *iter << " ";
    }
    std::cout << std::endl;
    
    for (auto elem : f1) {
        std::cout << elem << " ";
    }
    std::cout << std::endl;

    std::for_each(f1.begin(), f1.end(), [](int& elem) {
        std::cout << elem << " ";
    });
    std::cout << std::endl;
    return 0;
}
/*
before_begin : 1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
*/
  • 其它
#include <iostream>
#include <forward_list>
#include <algorithm> 
#include <list>

int main() {
    
    auto show = [](const char* str, const std::forward_list<int>& f) {
        std::cout << str << " : ";
        for (const auto& v : f) {
            std::cout << v << " ";
        }
        std::cout << std::endl;
    };

    std::forward_list<int> lst;
    std::forward_list<int>::iterator iter;

    //添加元素
    //iter = lst.insert_after(lst.begin(), 2); //错误
    //iter = lst.emplace_after(lst.end(), 2); //错误
    //lst.begin() == lst.end(), 不能在空项插入.
    iter = lst.insert_after(lst.before_begin(), 2);
    iter = lst.emplace_after(iter, 3);
    lst.emplace_front(1);
    lst.push_front(0);
    show("add ", lst);
    
    //删除元素
    lst.pop_front();
    show("pop_front", lst);
    lst.erase_after(lst.begin());
    show("erase", lst);
    lst.remove(3);
    show("remove=3", lst);
    lst.remove_if([](int& x) {return x == 1; });
    show("remove_if=1", lst);

    lst.assign({1, 2, 3, 4, 5});
    lst.resize(10, 9);
    show("resize", lst);

    lst.unique();
    show("unique", lst);

    lst.reverse();
    show("reverse", lst);

    lst.sort();
    show("sort", lst);
    return 0;
}
/*打印输出
add  : 0 1 2 3
pop_front : 1 2 3
erase : 1 3
remove=3 : 1
remove_if=1 :
resize : 1 2 3 4 5 9 9 9 9 9
unique : 1 2 3 4 5 9
reverse : 9 5 4 3 2 1
sort : 1 2 3 4 5 9
*/

3. 总结

通过上面的了解, std::forward_list只是对单链表进行一个简单的封装, 追求的是空间效率、性能。 非必要还是使用std::list吧。


c++ 疑难杂症(10) std::initializer_list

c++ 疑难杂症(9) std::array

c++ 疑难杂症(8) std::multimap

c++ 疑难杂症(7) std::tuple

c++ 疑难杂症(6) std::map

c++ 疑难杂症(5) std::pair

c++ 疑难杂症(4) std:vector

c++ 疑难杂症(3) 模板特化

c++ 疑难杂症(2) std::move

c++ 疑难杂症(1) std::thread

相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: