战斗包子
c++基本知识记录

c++基本知识记录

  • [[#标准库函数std::move()|标准库函数std::move()]]
  • [[#标准库函数std::stoll|标准库函数std::stoll]]
  • [[#成员初始化列表|成员初始化列表]]
  • [[#emplace_back|emplace_back]]
  • [[#函数的const关键字|函数的const关键字]]
  • [[#this指针|this指针]]
  • [[#lambda函数的作用域|lambda函数的作用域]]
  • [[#共享指针|共享指针]]
  • [[#共享指针#基本概念|基本概念]]
  • [[#共享指针#注意事项|注意事项]]

标准库函数std::move()

1
2
3
4
5
6
7
std::move()


// 头文件定义为
template <typename T>
typename std::remove_reference<T>::type&& move(T&& t) noexcept;

std::move 接受一个参数,并将其转换为右值引用。右值引用是绑定到临时对象的引用,它们可以用来指示资源的移动而不是复制。

  1. 返回局部对象:‌当函数需要返回一个局部对象时,‌使用std::move可以避免拷贝操作,‌直接返回对象的资源,‌从而提高性能。‌
  2. 传递临时对象:‌当需要将一个临时对象传递给另一个作用域时,‌使用std::move可以优化资源的转移,‌避免不必要的拷贝。‌
  3. 容器操作:‌在STL容器中操作时,‌使用std::move可以避免在插入或移动元素时发生的大量拷贝操作,‌从而提高容器操作的效率。‌
    例如
1
auto path = Path(std::move(LaneSemgent), 50, 50, 120, ego_pose);

可以将LaneSemgent临时实现Path的实例化,减少资源开销。

标准库函数std::stoll

C++ 标准库中的一个函数,用于将字符串转换为 long long 类型的整数。

1
2
3
int main() { std::string str = "123456789012345"; 
long long num = std::stoll(str); std::cout << "转换后的数字是: " << num << std::endl;
return 0; }

成员初始化列表

在C++中,构造函数名称后面跟着的冒号 (:) 是用来引入成员初始化列表(Member Initialization List)的。成员初始化列表是用来初始化类中的成员变量的一种方式,特别是当这些成员变量是引用或常量时,或者是其他需要通过构造函数来初始化的类对象时。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class BezierCurve {

public:

BezierCurve(const std::vector<Vec2d>& control_points)

: control_points_(control_points) {

if (control_points_.size() < 2) {

return;

}

double delta_x = control_points_.back().x() - control_points_.front().x();

double delta_y = control_points_.back().y() - control_points_.front().y();

distance_ =

std::sqrt(delta_x * delta_x + delta_y * delta_y); // 起点和终点的距离

}
......

这里的 : control_points_(control_points) 表示使用传入的 control_points 参数来直接初始化成员变量 control_points_。冒号后面的部分是在构造函数执行之前发生的成员变量的直接初始化。

emplace_back

emplace_back 是 C++11 中引入的一个 std::vector 容器的成员函数,它用于在容器的末尾直接构造一个元素。与 push_back 不同,emplace_back 允许你直接在容器内存中构造对象,而不需要创建一个临时对象然后再复制或移动它到容器中。

  1. 直接构造emplace_back 使用提供的参数直接在容器末尾构造元素,这通常通过调用元素的构造函数来实现。

  2. 性能优势:由于避免了临时对象的创建、复制或移动,emplace_back 可以在某些情况下提供更好的性能,尤其是当构造的对象类型不支持移动操作,或者移动操作的开销较大时。

  3. 参数转发emplace_back 支持完美转发,这意味着它可以接受任意类型的参数,并将其正确地转发给元素的构造函数。

  4. 用法emplace_back 的用法与 push_back 类似,但是它使用构造函数参数而不是一个已经存在的对象。

函数的const关键字

在C++中,函数定义中的const关键字放在参数列表之后,表示该函数承诺不会修改类的成员变量(也称为成员属性)。在您提供的函数签名bool Path::GetProjection(const Vec2d& point, double* accumulate_s, double* lateral, double* min_distance) const中,const关键字的具体含义如下:

  • const Vec2d& point:表示point参数是一个对常量的引用,这意味着函数内部不能修改point引用的值。

  • double* accumulate_s:表示accumulate_s是一个指向double类型的指针,函数可以修改通过这个指针所指向的值。

  • double* lateral:表示lateral是一个指向double类型的指针,函数可以修改通过这个指针所指向的值。

  • double* min_distance:表示min_distance是一个指向double类型的指针,函数可以修改通过这个指针所指向的值。

  • const:位于参数列表之后,表示GetProjection是一个常成员函数(也称为“不变成员函数”),意味着在执行过程中,该函数不会修改任何类的成员变量。

简而言之,const关键字在函数参数列表之后的使用,是为了保证调用该函数不会对对象的状态(成员变量)造成任何改变。这是面向对象编程中封装性和不变性的一个重要方面。

1
// GetProjection是一个常成员函数,它不会修改Path对象的任何成员变量 bool GetProjection(const Vec2d& point, double* accumulate_s, double* lateral, double* min_distance) const { // 函数体,可以读取成员变量,但不能修改它们 // ... }

this指针

在C++中,this指针是一个隐式的指针,它指向当前对象的实例。当你调用一个类的成员函数时,this指针指向当前对象的实例。这个指针在类的方法和构造函数中都是可用的,并且是唯一的,因为它是当前对象的指针。

this指针的类型是const T*,其中T是当前类的类型。这意味着你可以通过this指针来访问类的成员变量和方法。
(类似于python中的self)

1
2
3
4
5
6
7
8
class MyClass {
public:
int member;

void setMember(int value) {
this->member = value;
}
};

lambda函数的作用域

Lambda函数的作用域是指在lambda表达式中可以访问的变量和函数的范围。Lambda函数的作用域可以分为以下几种:

  1. 全局作用域

    • 在lambda表达式中,可以访问全局作用域中的变量和函数。
    • 全局作用域是指在lambda表达式定义的外部作用域。
  2. 局部作用域

    • 在lambda表达式中,可以访问局部作用域中的变量和函数。
    • 局部作用域是指在lambda表达式定义的内部作用域。
  3. 捕获作用域

    • 在lambda表达式中,可以使用捕获列表捕获局部作用域中的变量。
    • 捕获作用域是指在lambda表达式定义时,通过捕获列表捕获的变量和函数的作用域。

捕获列表用于指定lambda表达式中可以访问的变量和函数。捕获列表可以包含三种捕获方式:

  1. 值捕获(By Value)

    • 将局部变量的值复制到lambda表达式内部。
    • 例如:[x](int y) { return x + y; }
  2. 引用捕获(By Reference)

    • 将局部变量的引用传递到lambda表达式内部。
    • 例如:[&x](int y) { return x + y; }
  3. 捕获列表(Capture List)

    • 指定要捕获的变量和它们的捕获方式。
    • 例如:[x, &y](int z) { return x + y + z; }

在lambda表达式内部,可以按照捕获列表中的指定方式访问捕获的变量。如果捕获列表中没有指定要捕获的变量,那么lambda表达式内部不能访问局部作用域中的变量。

如果你在lambda表达式中捕获了this指针,那么你就可以直接访问对象的各个成员。this指针是一个隐式的指针,它指向当前对象的实例。在lambda表达式中捕获this指针意味着你可以在lambda内部访问和修改当前对象的成员变量和方法。

共享指针

共享指针(Shared Pointer)是C11标准库中引入的一种智能指针,用于实现共享所有权的概念。在C中,共享指针是通过<memory>头文件中的std::shared_ptr类模板实现的。共享指针的主要特点是多个共享指针可以指向同一个对象,并且这个对象会在最后一个共享指针被销毁或重置时自动销毁。

以下是共享指针的详细介绍:

基本概念

  • 所有权共享:多个shared_ptr实例可以共享对同一个对象的引用。每个shared_ptr都有一个关联的引用计数器,用于跟踪有多少个shared_ptr实例指向同一个对象。
  • 自动内存管理:当最后一个指向对象的shared_ptr被销毁或重置时,对象也会被自动销毁,通常是调用对象的析构函数。
1
2
3
4
5
6
7
8
9
10
#include <memory>

// 使用默认构造函数
std::shared_ptr<int> ptr1;

// 使用new表达式
std::shared_ptr<int> ptr2(new int(10));

// 使用make_shared函数,这是更推荐的方式,因为它可以减少内存分配的次数
std::shared_ptr<int> ptr3 = std::make_shared<int>(20);
1
2
3
4
5
ptr3.reset(); // 重置指针,对象将被销毁(如果这是最后一个指向它的指针)
ptr3.reset(new int(40)); // 重置指针,指向新的对象

size_t count = ptr2.use_count(); // 获取引用计数
bool isUnique = ptr2.unique(); // 检查是否是唯一指针

注意事项

  • 循环引用:当两个或多个对象通过共享指针相互引用时,可能会发生循环引用,导致内存泄漏。为了解决这个问题,可以使用弱共享指针(std::weak_ptr)。
  • 性能开销:共享指针比原始指针更大,因为它们需要额外的空间来存储引用计数和控制块。此外,引用计数的增加和减少可能会引入性能开销。
本文作者:战斗包子
本文链接:https://paipai121.github.io/2024/09/10/学习记录/c++基本知识记录/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可