在讲解高级初始化技术之前,先看一个前置背景,使用下面的类来方便地说明何时调用它的特殊成员函数。这样,我们就能看到额外的临时对象。
展开
代码语言:C++
自动换行
AI代码解释
struct MyType { MyType() { std::cout << "MyType default\n"; } explicit MyType(std::string str) : str_(std::move(str)) { std::cout << std::format("MyType {}\n", str_); } ~MyType() { std::cout << std::format("~MyType {}\n", str_); } MyType(const MyType& other) : str_(other.str_) { std::cout << std::format("MyType copy {}\n", str_); } MyType(MyType&& other) noexcept : str_(std::move(other.str_)) { std::cout << std::format("MyType move {}\n", str_); } MyType& operator=(const MyType& other) { if (this != &other) str_ = other.str_; std::cout << std::format("MyType = {}\n", str_); return *this; } MyType& operator=(MyType&& other) noexcept { if (this != &other) str_ = std::move(other.str_); std::cout << std::format("MyType = move {}\n", str_); return *this; } std::string str_; };
现在可以从相对简单但基本的元素开始。
二、reserve 结合 emplace_back
C++中的vector是一种可以根据需要增长的动态数组。但是,每次向量增长超过其当前容量时,它可能需要重新分配内存,这代价是昂贵的。为了优化这一点,可以使用reserve()方法结合emplace_back()。
reserve方法不改变vector的大小,但确保vector有足够的已分配内存来存储指定数量的元素。通过提前预留空间,可以防止在向向量添加元素时进行多次重新分配。
示例:
展开
代码语言:C++
自动换行
AI代码解释
#include <iostream> #include <string> #include <vector> #include <format> struct MyType { MyType() { std::cout << "MyType default\n"; } explicit MyType(std::string str) : str_(std::move(str)) { std::cout << std::format("MyType {}\n", str_); } ~MyType() { std::cout << std::format("~MyType {}\n", str_); } MyType(const MyType& other) : str_(other.str_) { std::cout << std::format("MyType copy {}\n", str_); } MyType(MyType&& other) noexcept : str_(std::move(other.str_)) { std::cout << std::format("MyType move {}\n", str_); } MyType& operator=(const MyType& other) { if (this != &other) str_ = other.str_; std::cout << std::format("MyType = {}\n", str_); return *this; } MyType& operator=(MyType&& other) noexcept { if (this != &other) str_ = std::move(other.str_); std::cout << std::format("MyType = move {}\n", str_); return *this; } std::string str_; }; int main() { { std::cout << "--- push_back\n"; std::vector<MyType> vec; vec.push_back(MyType("First")); std::cout << std::format("capacity: {}\n", vec.capacity()); vec.push_back(MyType("Second")); } { std::cout << "--- emplace_back\n"; std::vector<MyType> vec; vec.emplace_back("First"); std::cout << std::format("capacity: {}\n", vec.capacity()); vec.emplace_back("Second"); } { std::cout << "--- reserve() + emplace_\n"; std::vector<MyType> vec; vec.reserve(2); // Reserve space for 2 elements vec.emplace_back("First"); vec.emplace_back("Second"); } }
输出:
展开
代码语言:JavaScript
自动换行
AI代码解释
--- push_back MyType First MyType move First ~MyType capacity: 1 MyType Second MyType move Second MyType move First ~MyType ~MyType ~MyType First ~MyType Second --- emplace_back MyType First capacity: 1 MyType Second MyType move First ~MyType ~MyType First ~MyType Second --- reserve() + emplace_ MyType First MyType Second ~MyType First ~MyType Second
在这个例子中,可以看到三种插入技术之间的比较:
push_back()。emplace_back()。reserve()结合emplace_back。
第一种情况下,必须将临时对象传递给push_back,并移动它们来初始化vector的元素。但是还有一个重新分配,因为当添加第二个元素时,vector必须增长。
相对而言,emplace_back()技术更好,更容易编写,因为没有创建临时对象。
但是,第三种选择是最有效的,因为可以预先预留空间,然后在适当的地方创建元素。
通过使用reserve和emplace_back,可以确保vector在添加元素到预留容量时不需要重新分配内存。这种组合是优化性能的一种强大方式,特别是在向vector`中添加多个元素时。
三、C++ 20的constinit
constinit是一个强大的工具,用于强制常量初始化,特别是对于静态或线程局部变量。这个关键字在C++ 20中引入,它解决了C++中一个长期存在的难题:静态初始化顺序的问题。通过确保变量在编译时初始化,constinit提供了一个更可预测和更安全的初始化过程。
在其核心,constinit保证它所限定的变量在编译时被初始化。这对全局变量或静态变量尤其有益,可以确保它们不受动态初始化顺序问题的影响。
示例:
展开
代码语言:C++
自动换行
AI代码解释
#include <array> // 编译期初始化 constexpr int compute(int v) { return v*v*v; } constinit int global = compute(10); // 这个将不再起作用: // constinit int another = global; int main() { // 但允许以后更改…… global = 100; // global is not constant! // std::array<int, global> arr; }
在上面的代码中,全局变量是在编译时使用compute函数初始化的。然而,与const或constexpr不同,constinit不会使变量不可变。也就是说,虽然它的初始值是在编译时设置的,但可以在运行时对其进行修改,如main函数所示。此外,由于constinit变量不是constexpr,因此不能使用它初始化另一个constinit对象(如其他的int)。
四、Lambda表达式和初始化
C++ 14对Lambda捕获进行了重大更新,引入了在Lambda捕获子句中直接初始化新数据成员的能力。这个特性称为带有初始化器的捕获或广义Lambda捕获,它在使用Lambda时为我们提供了更大的灵活性和精度。
传统上,Lambda表达式可以从其封闭范围捕获变量。在C++ 14中,现在可以直接在捕获子句中创建和初始化新的数据成员,使Lambdas更加通用。
https://www.dongchedi.com/article/7594176187270693401
https://www.dongchedi.com/article/7594176654025589273
https://www.dongchedi.com/article/7594174513613636120
https://www.dongchedi.com/article/7594173614161723966
https://www.dongchedi.com/article/7594174316762726937
https://www.dongchedi.com/article/7594174486359114264
https://www.dongchedi.com/article/7594172209028399641
https://www.dongchedi.com/article/7594172028136112665
https://www.dongchedi.com/article/7594170708973158937
https://www.dongchedi.com/article/7594171822011318809
https://www.dongchedi.com/article/7594169237096940057
https://www.dongchedi.com/article/7594169267902857753
https://www.dongchedi.com/article/7594154183356727870
https://www.dongchedi.com/article/7594153895329448472
https://www.dongchedi.com/article/7594153335339647550
https://www.dongchedi.com/article/7594149462356804121
https://www.dongchedi.com/article/7594143242124427801
https://www.dongchedi.com/article/7594143151032959513
https://www.dongchedi.com/article/7594143310076477976
https://www.dongchedi.com/article/7594143261762585112
https://www.dongchedi.com/article/7594143234042380824
https://www.dongchedi.com/article/7594143047861420569
https://www.dongchedi.com/article/7594143261762257432
https://www.dongchedi.com/article/7594113295314305561
https://www.dongchedi.com/article/7594111799855956505
https://www.dongchedi.com/article/7594110342540673598
https://www.dongchedi.com/article/7594110249179578904
https://www.dongchedi.com/article/7594109373581492761
https://www.dongchedi.com/article/7594199698655724056
https://www.dongchedi.com/article/7594197415100793369
https://www.dongchedi.com/article/7594197322150904382
https://www.dongchedi.com/article/7594196529834181145
https://www.dongchedi.com/article/7594196856478368281
https://www.dongchedi.com/article/7594195826612781592
https://www.dongchedi.com/article/7594195431069762072
https://www.dongchedi.com/article/7594195431069270552
https://www.dongchedi.com/article/7594179258625802776
https://www.dongchedi.com/article/7594177577032991257
https://www.dongchedi.com/article/7594179258625409560
https://www.dongchedi.com/article/7594177972484309529
https://www.dongchedi.com/article/7594176579102884414
https://www.dongchedi.com/article/7594177062877839897
https://www.dongchedi.com/article/7594174721596473881
https://www.dongchedi.com/article/7594175192449008153
https://www.dongchedi.com/article/7594173652875444760
https://www.dongchedi.com/article/7594172550394069566
https://www.dongchedi.com/article/7594172678253265470
https://www.dongchedi.com/article/7594171407253275198
https://www.dongchedi.com/article/7594169982704173593
https://www.dongchedi.com/article/7594171805393650201
https://www.dongchedi.com/article/7594171076024812094
https://www.dongchedi.com/article/7594169163703271998
https://www.dongchedi.com/article/7594155915663180313
https://www.dongchedi.com/article/7594152900747100734
https://www.dongchedi.com/article/7594151966180426264
https://www.dongchedi.com/article/7594148426036904473
https://www.dongchedi.com/article/7594143100311192088
https://www.dongchedi.com/article/7594143206229705278
https://www.dongchedi.com/article/7594143047860961817
https://www.dongchedi.com/article/7594143133597205054
https://www.dongchedi.com/article/7594143172075487806
https://www.dongchedi.com/article/7594143133597073982
https://www.dongchedi.com/article/7594142854390759961
https://www.dongchedi.com/article/7594111120601039384
https://www.dongchedi.com/article/7594111426885583384
https://www.dongchedi.com/article/7594112371485393470
https://www.dongchedi.com/article/7594109925660426776
https://www.dongchedi.com/article/7594108812211438104