【ORB-slam2代码读懂】C++知识

目录

1、std::set

特点

常用方法

2、std::ref

什么是 std::reference_wrapper?

为什么需要 std::ref?

基本用法

3、多线程调用

线程 threadH

 线程 threadF

 实际应用

4、三元运算符 

 代码举例

5、枚举类型 eSensor

类型

解释

声明和初始化

条件判断

作为函数参数

示例代码

输出结果


1、std::set

   C++ 标准库中的一个关联容器,它存储唯一元素的集合,并且这些元素是自动排序的。每个元素只能出现一次,因为 std::set 内部使用的是平衡二叉查找树(通常是红黑树)来实现,这保证了其成员函数如插入、删除和查找等操作的时间复杂度为对数级别 O(log n)。

特点

  • 唯一性:集合中的所有元素都是唯一的,不允许有重复值。
  • 有序性:集合中的元素默认按照升序排列,但可以通过自定义比较器来改变排序规则。
  • 双向迭代器std::set 提供了双向迭代器,允许从任何位置向前或向后遍历集合。
  • 动态大小:可以随时添加或删除元素,集合会自动调整大小。

 

常用方法

  • 构造函数

    • std::set<T> s; // 创建一个空的 set
    • std::set<T> s(begin, end); // 使用范围 [begin, end) 初始化 set
    • std::set<T> s(initializer_list); // 使用初始化列表创建 set
    • std::set<T> s(another_set); // 拷贝构造
  • 插入元素

    • s.insert(value); // 插入单个元素
    • s.insert(begin, end); // 插入一个范围内的元素
  • 删除元素

    • s.erase(element); // 删除指定的元素
    • s.erase(position); // 删除迭代器指向的位置
    • s.erase(start, end); // 删除一个范围内的元素
  • 查找元素

    • s.find(element); // 查找指定元素,返回一个迭代器指向该元素,如果找不到则返回 end()
  • 检查元素是否存在

    • s.count(element); // 如果存在返回 1,否则返回 0
  • 获取大小

    • s.size(); // 返回集合中元素的数量
  • 清空集合

    • s.clear(); // 移除所有元素
  • 迭代器

    • s.begin(); // 返回指向第一个元素的迭代器
    • s.end(); // 返回指向最后一个元素之后位置的迭代器
  • 排序规则

    • s.key_comp(); // 返回一个比较对象,可用于比较两个键值
    • s.value_comp(); // 返回一个比较对象,可用于比较两个元素
#include <iostream>
#include <set>

int main() {
    std::set<int> numbers;

    // 插入元素
    numbers.insert(10);
    numbers.insert(30);
    numbers.insert(20);

    // 输出集合中的所有元素
    for (const auto& num : numbers) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    // 查找元素
    if (numbers.find(20) != numbers.end()) {
        std::cout << "找到了20" << std::endl;
    }

    // 删除元素
    numbers.erase(20);

    // 检查是否成功删除
    if (numbers.find(20) == numbers.end()) {
        std::cout << "20 已经被删除" << std::endl;
    }

    return 0;
}

 注释:

for (const auto& num : numbers)

这是一个范围 for 循环(也称为基于范围的 for 循环),它用于遍历容器中的所有元素。这里的 numbers 是一个 std::set<int> 类型的容器。

  • const auto& num:

    • auto: 编译器会根据 numbers 容器中的元素类型自动推断 num 的类型。因为 numbers 是一个 std::set<int>,所以 num 的类型会被推断为 int

    • const: 表示 num 是一个常量引用,意味着你不能通过 num 修改 numbers 中的元素。

    • &: 表示 num 是一个引用,而不是一个新的变量。引用是原元素的别名,因此不会创建额外的副本,这在处理大型对象时可以提高性能。

  • numbers: 这是你遍历的容器,这里是一个 std::set<int>

  • 2、std::ref

  • 什么是 std::reference_wrapper

    std::reference_wrapper 是一个模板类,包装了一个引用。它提供了与原始引用类似的接口,但可以被传递和存储在容器中,而不会导致值的拷贝。

    为什么需要 std::ref

  • 避免拷贝:对于大型对象或复杂数据结构,传递引用可以避免不必要的拷贝,提高性能。

  • 传递引用:某些函数(如 std::thread 构造函数)需要传递可复制的对象,而不仅仅是引用。std::ref 可以将引用转换为可复制的对象。

  • 基本用法

  • #include <iostream>
    #include <functional>
    #include <thread>
    
    void printValue(int& value) {
        std::cout << "Value: " << value << std::endl;
    }
    
    int main() {
        int x = 10;
    
        // 使用 std::ref 包装引用
        std::reference_wrapper<int> ref_x = std::ref(x);
    
        // 传递引用给函数
        printValue(ref_x);
    
        // 修改原始值
        x = 20;
        printValue(ref_x);
    
        return 0;
    }

  • 3、多线程调用

 代码中使用了 std::thread 来启动两个线程,分别调用 FindHomographyFindFundamental 方法。

线程 threadH

thread threadH(&Initializer::FindHomography, this, ref(vbMatchesInliersH), ref(SH), ref(H));
  • &Initializer::FindHomography:指向 Initializer 类的成员函数 FindHomography

  • this:当前对象的指针,用于传递给成员函数。

  • ref(vbMatchesInliersH):使用 std::ref 包装的 vbMatchesInliersH 引用,确保传递的是引用而不是值。

  • ref(SH):使用 std::ref 包装的 SH 引用。

  • ref(H):使用 std::ref 包装的 H 引用

 线程 threadF

thread threadF(&Initializer::FindFundamental, this, ref(vbMatchesInliersF), ref(SF), ref(F));
  • &Initializer::FindFundamental:指向 Initializer 类的成员函数 FindFundamental
  • this:当前对象的指针,用于传递给成员函数。
  • ref(vbMatchesInliersF):使用 std::ref 包装的 vbMatchesInliersF 引用。
  • ref(SF):使用 std::ref 包装的 SF 引用。
  • ref(F):使用 std::ref 包装的 F 引用。

 实际应用

 在实际应用中,启动

线程后需要确保线程能够正确地完成任务。通常需要等待所有线程完成后再继续执行后续代码。这可以通过 std::threadjoin 方法来实现:

bool Initializer::Initialize(const Frame &CurrentFrame) {
    // ...
    thread threadH(&Initializer::FindHomography, this, ref(vbMatchesInliersH), ref(SH), ref(H));
    thread threadF(&Initializer::FindFundamental, this, ref(vbMatchesInliersF), ref(SF), ref(F));

    // 等待线程完成
    threadH.join();
    threadF.join();

    // 继续执行其他初始化步骤
    // ...

    return true; // 或者根据实际情况返回适当的值
}

4、三元运算符 

 代码举例

std::cout << "Sensor type: " << (m_sensor == eSensor::MONOCULAR ? "Monocular" : (m_sensor == eSensor::STEREO ? "Stereo" : "RGB-D")) << std::endl;

在这行代码中,三元运算符是嵌套使用的,以便处理多个条件。让我们逐步拆解:

  1. 外层三元运算符

    m_sensor == eSensor::MONOCULAR ? "Monocular" : (...)

    • 条件m_sensor == eSensor::MONOCULAR
    • 如果条件为 true:返回字符串 "Monocular"
    • 如果条件为 false:执行内层三元运算符
  2. 内层三元运算符

    m_sensor == eSensor::STEREO ? "Stereo" : "RGB-D"
    • 条件m_sensor == eSensor::STEREO
    • 如果条件为 true:返回字符串 "Stereo"
    • 如果条件为 false:返回字符串 "RGB-D"

5、枚举类型 eSensor

     在 C++ 中,枚举类型(enum)是一种用户定义的数据类型,用于定义一组命名的整数常量。枚举类型可以提高代码的可读性和可维护性,因为它为特定的值赋予了有意义的名称。

类型

enum class eSensor {
    MONOCULAR,
    STEREO,
    RGBD
};

解释

  1. enum class

    • enum class 是 C++11 引入的一种强类型枚举。与传统的 enum 不同,enum class 的枚举值具有强类型检查,不能与其他枚举类型或整数类型混用。
    • 例如,eSensor::MONOCULAR 是 eSensor 类型的,不能直接赋值给 int 类型的变量。
  2. 枚举值

    • MONOCULAR:表示单目传感器。
    • STEREO:表示立体传感器。
    • RGBD:表示 RGB-D 传感器(深度传感器)。

声明和初始化

eSensor sensorType = eSensor::MONOCULAR;

条件判断

if (sensorType == eSensor::MONOCULAR) {
    std::cout << "Using Monocular sensor." << std::endl;
} else if (sensorType == eSensor::STEREO) {
    std::cout << "Using Stereo sensor." << std::endl;
} else if (sensorType == eSensor::RGBD) {
    std::cout << "Using RGB-D sensor." << std::endl;
}

作为函数参数

void configureSensor(eSensor sensor) {
    switch (sensor) {
        case eSensor::MONOCULAR:
            std::cout << "Configuring Monocular sensor." << std::endl;
            break;
        case eSensor::STEREO:
            std::cout << "Configuring Stereo sensor." << std::endl;
            break;
        case eSensor::RGBD:
            std::cout << "Configuring RGB-D sensor." << std::endl;
            break;
        default:
            std::cout << "Unknown sensor type." << std::endl;
            break;
    }
}

示例代码

下面是一个完整的示例,展示了如何定义和使用 eSensor 枚举类型:

#include <iostream>
#include <string>

// 定义枚举类型 eSensor
enum class eSensor {
    MONOCULAR,
    STEREO,
    RGBD
};

// 定义 System 类
class System {
public:
    // 构造函数
    System(const std::string &strVocFile, std::string &strSettingsFile, const eSensor sensor, const bool bUseViewer = true)
        : m_strVocFile(strVocFile), m_strSettingsFile(strSettingsFile), m_sensor(sensor), m_bUseViewer(bUseViewer) {
        // 初始化系统
        std::cout << "Initializing system with vocabulary file: " << m_strVocFile << std::endl;
        std::cout << "Settings file: " << m_strSettingsFile << std::endl;

        // 使用三元运算符输出传感器类型
        std::string sensorType = (m_sensor == eSensor::MONOCULAR ? "Monocular" :
                                  (m_sensor == eSensor::STEREO ? "Stereo" : "RGB-D"));
        std::cout << "Sensor type: " << sensorType << std::endl;

        std::cout << "Use viewer: " << (m_bUseViewer ? "Yes" : "No") << std::endl;
    }

private:
    std::string m_strVocFile;
    std::string m_strSettingsFile;
    eSensor m_sensor;
    bool m_bUseViewer;
};

int main() {
    std::string vocFile = "vocabulary.txt";
    std::string settingsFile = "settings.yaml";

    // 创建 System 对象
    System system(vocFile, settingsFile, eSensor::STEREO);

    return 0;
}

输出结果

运行这段代码后,控制台的输出将是:

Initializing system with vocabulary file: vocabulary.txt
Settings file: settings.yaml
Sensor type: Stereo
Use viewer: Yes
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值