目录
1.1
STL可以被划分为4个概念库:
1.容器库:管理和存储数据的容器;
2.迭代器库:迭代器是类似于指针的对象,通常被用于引用容器类的对象序列;
3.算法库:定义了一些能运用到容器中的元素上的通用算法;
4.数值库:定义了一些通用的数学函数和一些对容器元素进行数值处理的操作。以及一些用于随机数生成的高级函数。
1.2
错误代码:
template <typename T>
T& larger(T& a, T& b) {
return a > b ? a : b;
}
template <typename T>
T& test(T& a) {
return a ;
}
int main() {
int x = 2;
double y = 3.5;
double& t = larger<double>(x, y);
test<double>(x);
return 0;
}
larger要求两个参数类型一致;当显示模板参数的类型后,传入的实参类型应与显示模板参数类型一致。
1.3
除非对象是右值(临时对象),所有STL容器存储的都是对象的副本,修改容器内对象不会影响原对象。
然而,从容器中获取对象是获取对象引用,修改引用的同时会修改容器内原对象。
不要在以基类为元素的容器中存放派生类,会导致派生类对象的切片;应该使用以基类指针或基类智能指针为元素的容器。
1.4 迭代器
递增迭代器:std::begin() \ std::end()
反向递增迭代器: std::rend() \ std::rbegin() \ base():基础迭代器:总是指向反向迭代器指向的下一位置。
插入迭代器:
移动迭代器:
1.5 迭代器上的运算
advance() | 两个参数,第一个是迭代器,第二个是整数n | 让迭代器向前走几个 | 输入迭代器 |
distence() | 两个参数,两个都是迭代器 | 返回两个迭代器之间的元素个数 | |
next() | 两个参数,第一个是迭代器,第二个是整数n | 正向迭代器 | |
prev() | 两个参数,第一个是迭代器,第二个是整数n | 双向迭代器 |
1.6智能指针
和原始指针的区别:
1.智能指针只能用来保存堆上分配的内存的地址
2.不能自增自减。
一、unique_ptr<T>:
唯一指向对象,独享对象的所有权。当不需要使用多个智能指针,想独享所有权时选择unique_ptr<T>。
不能以传值的方式将一个unique_ptr<T>对象传入函数,因为unique_ptr<T>不支持拷贝,必须使用引用的方式。可以作为函数的返回值。
通过unique_ptr<T>.get()可以获取unique_ptr<T>的原始指针。
auto unique_p = std::make_unique<std::string>(6,'*');
std::string pstr {unique_p.ger()};
使用reset()析构unique_ptr<T>所指向的对象。也可以将新对象的地址值传给reset()函数
auto pname = std::make_unique<std::string>("aaaa")
pname.reset(new std::string{"FFFFF"})
不能复制unique_ptr<T>,可以使用release()转移对象所有权;
auto pname = std::make_unique<std::string>("aaaa")
std::unique_ptr<std::string> new_name{pname.release()};
使用swap()交换两个指针指向的对象:
pname1.swap(pname2);
比较和检查两个unique_ptr<T>:
比较两个unique_ptr<T>对象就是比较get()后的地址;
unique_ptr<T>可以隐式的转换为布尔值,当对一个unique_ptr<T>对象调用reset()和release()时要先做这种检查;
二、shared_ptr<T>:
当需要多个指针指向一个对象时,或者需要拷贝一个存放了智能指针的容器,使用shared_ptr<T>。
通过make_shared<T>()创建shared_ptr<T>更有效率。
可以用一个定义好的shared_ptr<T>初始化另一个shared_ptr<T>;也可以将一个shared_ptr<T>赋值给另一个shared_ptr<T>;
如果要创建一个指向数组的shared_ptr<T>,就必须为智能指针提供一个delete函数去释放数组的堆内存,所以最好使用array<T> vector<T>.
reset()与unique_ptr相同;
unique()可以检查shared_ptr<T>对象是否有任何副本;
use_count()返回当前被调用对象的实例个数。
三、weak_ptr<T>:
可以从shared_ptr<T>或已有的shared_ptr<T>创建一个weak_ptr<T>对象;weak_ptr<T>对象用来解决引用循环问题。
auto pData = std::make_sharedd<T>();
std::weak_ptr<T> pwData {pData};
std::weak_ptr<T> pwData2 {pwData};
1.判断指向的对象是否仍然存在,这样意味着仍然有shared_ptr对象指向它;
pwData.expired() 如果对象不存在的话expired()会返回true;
2.从一个weak_ptr<T>对象创建一个shared_ptr<T>对象;
std::shared_ptr<T> pNew {pwData.lock()};
1.8 把函数作为实参传入
函数对象也被称为仿函数,就是重载了函数调用运算符operator()()的类对象。
lambda表达式 :
[=]()mutable
如果方括号内是 = ,就能以值的形式访问封闭范围内的自动变量,就是说在lambda表达式里可以使用所有变量但是不能改变他们的值,加上mutable就可以改变变量副本的值。
如果方括号内是 & ,变量的值就能在lambda内改变,并且不用加mutable。
课后练习:
pe1.2(来自gpt):
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
int main() {
std::array<std::string, 5> words = { "Hello", "world", "from", "OpenAI", "Assistant" };
// Define a lambda function to replace vowels with '*'
auto replaceVowels = [](std::string& word) {
std::string vowels = "aeiou";
for (auto it = word.begin(); it != word.end(); ++it) {
if (std::find(vowels.begin(), vowels.end(), std::tolower(*it)) != vowels.end()) {
*it = '*';
}
}
return word;
};
// Apply transform() with the lambda function
std::transform(words.begin(), words.end(), words.begin(), replaceVowels);
// Print the modified words
std::cout << "Modified words:\n";
for (const auto& word : words) {
std::cout << word << "\n";
}
return 0;
}
pe1.3:
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
int main() {
std::array<std::string, 5> words = { "Hello", "world", "from", "OpenAI", "Assistant" };
// Define a lambda function to replace vowels with '*'
auto replaceVowels = [](std::string& word) {
auto to_up = [](char c) {return toupper(c); };
transform(begin(word), end(word), begin(word), to_up);
return word;
};
// Apply transform() with the lambda function
std::transform(words.begin(), words.end(), words.begin(), replaceVowels);
// Print the modified words
std::cout << "Modified words:\n";
for (const auto& word : words) {
std::cout << word << "\n";
}
return 0;
}