std::array与std::vector不一样的是,array对象的大小是固定的,若是容器大小是固定的,那么能够优先考虑使用std::array容器。ios
因为std::vector是自动扩容的,当存入大量的数据后,而且对容器进行了删除操做,容器并不会自动归还被删除元素相应的内存,这时候须要手动运行shrink_to_fit()释放这部份内存。c++
std::array C风格接口传参:函数
void foo(int *p, int len){ return; } std::array<int, 4> arr = {1,2,3,4}; //foo(arr,arr.size()); //非法,没法隐式转换 foo(&arr[0], arr.size()); foo(arr.data(), arr.size()); //使用std::sort std::sort(arr.begin(), arr.end()); //升序 std::sort(arr.begin(), arr.end(), [](int a, int b){ return b > a; })
std::forward_list是一个列表容器,使用方法和std::list基本相似。和list的双向链表的实现不一样,forward_list使用单向链表进行实现,提供了O(1)复杂度的元素插入,不支持快速随机访问,也是标准库容器中惟一一个不提供size()方法的容器。当不须要双向迭代时,具备比list更高的空间利用率。性能
传统c++中的有序容器 std::map / std::set,这些元素内部经过红黑树进行实现,插入和搜索的平均复杂度均为O(log(size))。在插入元素时,会根据<操做符比较元素大小并判断元素是否相同,并选择合适的位置插入到容器中。当对这个容器中的元素进行遍历时,输出结果会按照<操做符的顺序来逐个遍历。spa
而无序容器中的元素是不进行排序的,内部经过Hash表实现,插入和搜索元素的平均复杂度为O(constant),在不关心容器内部元素顺序时,可以得到显著的性能提高。c++11
c++11引入了两组无序容器:std::unordered_map / std::unordered_multimap和std::unordered_set / std::unordered_multiset。
它们的用法和原有的std::map / std::multimap / std::set / std::multiset基本相似。code
#include <iostream> #include <string> #include <unordered_map> #include <map> using namespace std; int main(){ unordered_map<int, string> u = { {1, "1"}, {3, "3"}, {2, "2"} }; map<int, string> v = { {1, "1"}, {3, "3"}, {2, "2"} }; cout << "std::unordered_map" << endl; for(const auto &n : u){ cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n"; } cout <<endl; cout << "std::map" << endl; for (const auto & n : v){ cout << "Key:[" << n.first << "] Value:[" << n.second << "]\n"; } }
传统c++中的容器,除了std::pair外,彷佛没有现成的结构可以用来存放不一样类型的数据。但std::pair的缺陷是显而易见的,只能保存两个元素。对象
三个核心函数:
一、std::make_tuple: 构造元组
二、std::get:得到元组某个位置的值
三、std::tie:元组拆包排序
#include <iostream> #include <tuple> using namespace std; auto get_student(int id){ switch (id) { case 0: return make_tuple(3.8, 'A', "张三"); break; case 1: return make_tuple(2.9, 'C', "李四"); break; case 2: return make_tuple(1.7, 'D', "王五"); break; default: return make_tuple(0.0, 'D', "null"); break; } } int main(){ auto student = get_student(0); std::cout << "ID: 0, " << "GPA: " << get<0>(student) << ", " << "成绩:" << get<1>(student) << ", " << "姓名:" << get<2>(student) << "\n"; double gpa; char grade; string name; //元祖进行拆包 tie(gpa, grade, name) = get_student(1); std::cout << "ID: 1, " << "GPA: " << gpa << ", " << "成绩:" << grade << ", " << "姓名:" << name << "\n"; return 0; }
std::get除了使用常量获取元组对象外,c++14增长了使用类型来获取元组中的对象:索引
std::tuple<std::string, double, double, int> t("123", 4.5, 6.7, 8); std::cout << std::get<std::string>(t) << std::endl; std::cout << std::get<double>(t) << std::endl; //非法,引起编译期错误 std::cout << std::get<int>(t) << std::endl;
std::get<>依赖一个编译期的常量,因此下面的方式是不合法的:
int index = 1; std::get<index>(t); //非法
c++17引入了std::variant<>,提供给variant<>的类型模版参数 可让一个variant<>从而容纳提供的几种类型的变量(在其余语言,例如Python/JavaScrpit等,表现为动态类型):
#include <variant> template <size_t n, typename... T> constexpr std::variant<T...> _tuple_index(const std::tuple<T...>& tpl, size_t i){ if constexpr(n >= sizeof...(T)) throw std::out_of_range("越界."); if(i == n) return std::variant<T...>{ std::in_place_index<n>, std::get<n>(tpl) }; return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(tpl, i); } template <typename... T> constexpr std::variant<T...> tuple_index(const std::tuple<T...>& tpl, size_t i){ return _tuple_index<0>(tpl, i); } template <typename T0, typename ... TS> std::ostream & operator<< (std::ostream & s, std::variant<T0, TS...> const & v){ std::visit([&](auto && x){s<<x;}, v); return s; }
这样咱们就能:
int i = 1; std::cout << tuple_index(student, i) << endl;
还有一个常见的需求就是合并两个元组,这能够经过std::tuple_cat来实现:
auto new_tuple = std::tuple_cat(get_student(1), std::move(t));
要遍历首先咱们须要知道一个元组的长度,能够:
template <typename T> auto tuple_len(T &tpl){ return std::tuple_size<T>::value; }
这样就可以对元组进行迭代了:
//迭代 for(int i = 0; i != tuple_len(new_tuple); ++i){ //运行期索引 std::cout << tuple_index<i, new_tuple) << std::endl; }
std::tuple虽然有效,可是标准库提供的功能有限,没办法知足运行期索引和迭代的需求,好在咱们还有其余办法能够自行实现。