【ORB-slam2代码读懂】2、System 类的构造函数

目录

整体函数

各部分以及作用 

构造函数声明

初始化列表

构造函数体

Step 1: 初始化各成员变量

Step 2: 创建三大线程

Step 3: 设置线程间通信

相关C++基础知识 

 new操作符

基本用法

1. 分配单个对象

2. 分配数组

释放内存

1. 释放单个对象

2. 释放数组

构造函数和析构函数

动态分配和智能指针

使用 std::unique_ptr

使用 std::shared_ptr

常见用途

MyClass 类

示例代码

输出结果

解释

总结

-> 运算符

基本用法

1. 访问对象的成员方法

2. 访问对象的数据成员

工作原理

等价形式


整体函数

System::System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer) : 
        mSensor(sensor), mpViewer(static_cast<Viewer *>(NULL)), mbReset(false), mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false) {
	
	// step1. 初始化各成员变量
	// step1.1. 读取配置文件信息
    cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
	// step1.2. 创建ORB词袋
    mpVocabulary = new ORBVocabulary();
    // step1.3. 创建关键帧数据库,主要保存ORB描述子倒排索引(即根据描述子查找拥有该描述子的关键帧)
	mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
	// step1.4. 创建地图
    mpMap = new Map();

	// step2. 创建3大线程: Tracking、LocalMapping和LoopClosing
    // step2.1. 主线程就是Tracking线程,只需创建Tracking对象即可
	mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer, mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
	// step2.2. 创建LocalMapping线程及mpLocalMapper
    mpLocalMapper = new LocalMapping(mpMap, mSensor==MONOCULAR);
    mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run, mpLocalMapper);
	// step2.3. 创建LoopClosing线程及mpLoopCloser
    mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor!=MONOCULAR);
    mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser);
            
	// step3. 设置线程间通信
	mpTracker->SetLocalMapper(mpLocalMapper);
    mpTracker->SetLoopClosing(mpLoopCloser);
    mpLocalMapper->SetTracker(mpTracker);
    mpLocalMapper->SetLoopCloser(mpLoopCloser);
    mpLoopCloser->SetTracker(mpTracker);
    mpLoopCloser->SetLocalMapper(mpLocalMapper);
}

该构造函数负责初始化视觉里程计系统

各部分以及作用 

构造函数声明

System::System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer)
    : mSensor(sensor), mpViewer(static_cast<Viewer *>(NULL)), mbReset(false), mbActivateLocalizationMode(false), mbDeactivateLocalizationMode(false) {

初始化列表

  • mSensor(sensor):将传入的传感器类型 sensor 赋值给成员变量 mSensor
  • mpViewer(static_cast<Viewer *>(NULL)):将成员变量 mpViewer 初始化为 nullptr
  • mbReset(false):将成员变量 mbReset 初始化为 false
  • mbActivateLocalizationMode(false):将成员变量 mbActivateLocalizationMode 初始化为 false
  • mbDeactivateLocalizationMode(false):将成员变量 mbDeactivateLocalizationMode 初始化为 false

构造函数体

Step 1: 初始化各成员变量

  1. 读取配置文件信息

    cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
    • cv::FileStorage:OpenCV 提供的一个类,用于读取和写入 XML 或 YAML 文件。
    • 参数strSettingsFile.c_str():配置文件的路径,转换为 C 风格字符串。       cv::FileStorage::READ:表示以读取模式打开文件。
    • 作用:读取配置文件 strSettingsFile,并将文件内容加载到 fsSettings 对象中
  2. 创建 ORB 词袋

    mpVocabulary = new ORBVocabulary();
    • ORBVocabulary:一个类,用于创建和管理 ORB 词袋。
    • 作用:创建一个新的 ORBVocabulary 对象,并将其指针赋值给 mpVocabulary
  3. 创建关键帧数据库

    mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
    • KeyFrameDatabase:一个类,用于管理关键帧和它们的描述子。
    • 参数*mpVocabulary:传递已创建的 ORB 词袋对象。
    • 作用:创建一个新的 KeyFrameDatabase 对象,并将其指针赋给 mpKeyFrameDatabase。关键帧数据库用于保存 ORB 描述子的倒排索引,以便快速查找关键帧。
  4. 创建地图

    mpMap = new Map();
    • Map:一个类,用于管理地图中的关键帧和路标点。
    • 作用:创建一个新的 Map 对象,并将其指针赋值给 mpMap

Step 2: 创建三大线程

  1. 创建 Tracking 线程

    mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer, mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
    • Tracking:一个类,负责相机的跟踪任务。
    • 参数
      • this:当前 System 对象的指针。
      • mpVocabulary:ORB 词袋对象的指针。
      • mpFrameDrawer:帧绘制对象的指针。
      • mpMapDrawer:地图绘制对象的指针。
      • mpMap:地图对象的指针。
      • mpKeyFrameDatabase:关键帧数据库对象的指针。
      • strSettingsFile:配置文件的路径。
      • mSensor:传感器类型。
    • 作用:创建一个新的 Tracking 对象,并将其指针赋值给 mpTrackerTracking 线程负责跟踪相机的位置和姿态。
  2. 创建 LocalMapping 线程

    mpLocalMapper = new LocalMapping(mpMap, mSensor == MONOCULAR);
    mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run, mpLocalMapper);
    • LocalMapping:一个类,负责局部地图的构建和优化。
    • 参数
      • mpMap:地图对象的指针。
      • mSensor == MONOCULAR:一个布尔值,表示传感器类型是否为单目。
    • 作用:创建一个新的 LocalMapping 对象,并将其指针赋值给 mpLocalMapper
    • std::thread:创建一个新的线程,调用 LocalMapping 对象的 Run 方法。
    • 参数
      • &ORB_SLAM2::LocalMapping::Run:指向 LocalMapping 类的 Run 方法的指针。
      • mpLocalMapper:传递 LocalMapping 对象的指针。
    • 作用:启动 LocalMapping 线程,开始局部地图的构建和优化
  3. 创建 LoopClosing 线程

    mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor != MONOCULAR);
    mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser);
    • LoopClosing:一个类,负责检测和修正闭环。
    • 参数
      • mpMap:地图对象的指针。
      • mpKeyFrameDatabase:关键帧数据库对象的指针。
      • mpVocabulary:ORB 词袋对象的指针。
      • mSensor != MONOCULAR:一个布尔值,表示传感器类型是否为非单目。
    • 作用:创建一个新的 LoopClosing 对象,并将其指针赋值给 mpLoopCloser
    • std::thread:创建一个新的线程,调用 LoopClosing 对象的 Run 方法。
    • 参数
      • &ORB_SLAM2::LoopClosing::Run:指向 LoopClosing 类的 Run 方法的指针。
      • mpLoopCloser:传递 LoopClosing 对象的指针。
    • 作用:启动 LoopClosing 线程,开始闭环检测和修正。

Step 3: 设置线程间通信

  1. 设置 Tracker 和 LocalMapper 之间的通信

    mpTracker->SetLocalMapper(mpLocalMapper);
    • 将 LocalMapping 对象的指针传递给 Tracking 对象,以便 Tracking 可以与 LocalMapping 通信。
  2. 设置 Tracker 和 LoopClosing 之间的通信

    mpTracker->SetLoopClosing(mpLoopCloser);
    • 将 LoopClosing 对象的指针传递给 Tracking 对象,以便 Tracking 可以与 LoopClosing 通信。
  3. 设置 LocalMapper 和 Tracker 之间的通信

    mpLocalMapper->SetTracker(mpTracker);
    • 将 Tracking 对象的指针传递给 LocalMapping 对象,以便 LocalMapping 可以与 Tracking 通信。
  4. 设置 LocalMapper 和 LoopClosing 之间的通信

    mpLocalMapper->SetLoopClosing(mpLoopCloser);
    • 将 LoopClosing 对象的指针传递给 LocalMapping 对象,以便 LocalMapping 可以与 LoopClosing 通信。
  5. 设置 LoopClosing 和 Tracker 之间的通信

    mpLoopCloser->SetTracker(mpTracker);
    • 将 Tracking 对象的指针传递给 LoopClosing 对象,以便 LoopClosing 可以与 Tracking 通信。
  6. 设置 LoopClosing 和 LocalMapper 之间的通信

    mpLoopCloser->SetLocalMapper(mpLocalMapper);
    • 将 LocalMapping 对象的指针传递给 LoopClosing 对象,以便 LoopClosing 可以与 LocalMapping 通信。

相关C++基础知识 

 new操作符

new 操作符在 C++ 中用于动态分配内存。与静态分配(在栈上分配内存)不同,new 在堆上分配内存,并返回指向该内存的指针。这意味着通过 new 分配的内存不会在函数结束时自动释放,需要手动使用 delete 操作符来释放内存。

基本用法

1. 分配单个对象
int *ptr = new int;  // 分配一个 int 类型的内存,并返回指向该内存的指针
*ptr = 10;           // 给分配的内存赋值
2. 分配数组
int *array = new int[5];  // 分配一个包含 5 个 int 类型元素的数组
for (int i = 0; i < 5; ++i) {
    array[i] = i;         // 给数组元素赋值
}

释放内存

1. 释放单个对象
delete ptr;  // 释放通过 new 分配的单个对象的内存
2. 释放数组
delete[] array;  // 释放通过 new[] 分配的数组的内存

构造函数和析构函数

当使用 new 分配对象时,会调用该对象的构造函数。同样,当使用 delete 释放对象时,会调用该对象的析构函数。

class MyClass {
public:
    MyClass() {
        std::cout << "Constructor called" << std::endl;
    }
    ~MyClass() {
        std::cout << "Destructor called" << std::endl;
    }
};

int main() {
    MyClass *obj = new MyClass();  // 调用 MyClass 的构造函数
    delete obj;                    // 调用 MyClass 的析构函数
    return 0;
}

动态分配和智能指针

为了避免内存泄漏, C++ 推荐使用智能指针(如 std::unique_ptrstd::shared_ptr)来管理动态分配的内存。

使用 std::unique_ptr
#include <memory>

int main() {
    std::unique_ptr<int> ptr(new int);  // 使用 unique_ptr 管理动态分配的内存
    *ptr = 10;
    return 0;
}  // 当 ptr 离开作用域时,内存会自动释放
使用 std::shared_ptr
#include <memory>

int main() {
    std::shared_ptr<int> ptr(new int);  // 使用 shared_ptr 管理动态分配的内存
    *ptr = 10;
    return 0;
}  // 当最后一个 shared_ptr 离开作用域时,内存会自动释放

常见用途

  1. 动态数组:当数组大小在编译时未知时,可以使用 new 动态分配数组。
  2. 对象池:在需要频繁创建和销毁对象的场景中,可以使用对象池来提高性能。
  3. 多态对象:当需要创建多态对象时,可以使用 new 分配基类指针指向派生类对象。

MyClass 类

class MyClass {
public:
    // 构造函数
    MyClass() {
        std::cout << "Constructor called" << std::endl;
    }

    // 析构函数
    ~MyClass() {
        std::cout << "Destructor called" << std::endl;
    }

    // 成员方法
    void display() {
        std::cout << "Displaying MyClass object" << std::endl;
    }
};

 

示例代码

让我们通过一个完整的示例来展示 MyClass 类的使用:

#include <iostream>

class MyClass {
public:
    // 构造函数
    MyClass() {
        std::cout << "Constructor called" << std::endl;
    }

    // 析构函数
    ~MyClass() {
        std::cout << "Destructor called" << std::endl;
    }

    // 成员方法
    void display() {
        std::cout << "Displaying MyClass object" << std::endl;
    }
};

int main() {
    // 动态分配单个对象
    MyClass *obj = new MyClass();

    // 通过指针调用对象的方法
    obj->display();  // 等价于 (*obj).display();

    // 释放内存
    delete obj;

    return 0;
}

输出结果

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

Constructor called
Displaying MyClass object
Destructor called

解释

  1. 构造函数调用

    • MyClass *obj = new MyClass();:创建一个 MyClass 对象,并将其指针赋值给 obj。此时会调用 MyClass 的构造函数,输出 Constructor called
  2. 调用 display 方法

    • obj->display();:通过指针 obj 调用 MyClass 对象的 display 方法,输出 Displaying MyClass object
    • 等价形式(*obj).display();,先通过指针 obj 获取指向的对象,然后调用该对象的 display 方法。
  3. 析构函数调用

    • delete obj;:释放通过 new 分配的 MyClass 对象的内存。此时会调用 MyClass 的析构函数,输出 Destructor called

总结

  • MyClass 类:定义了一个简单的类,包含构造函数、析构函数和一个成员方法 display
  • display 方法:用于显示 MyClass 对象的信息。
  • 指针调用方法:通过指针 obj 调用对象的方法 display,使用 -> 运算符。

-> 运算符

-> 运算符在 C++ 中用于通过指针访问对象的成员(方法或属性)。它结合了指针解引用和成员访问两个操作。

基本用法

1. 访问对象的成员方法
class MyClass {
public:
    void display() {
        std::cout << "Displaying MyClass object" << std::endl;
    }
};

int main() {
    MyClass *obj = new MyClass();  // 动态分配 MyClass 对象
    obj->display();                // 通过指针调用 display 方法
    delete obj;                    // 释放内存
    return 0;
}
2. 访问对象的数据成员
class MyClass {
public:
    int value;
};

int main() {
    MyClass *obj = new MyClass();  // 动态分配 MyClass 对象
    obj->value = 10;               // 通过指针访问并设置 value 成员
    std::cout << "Value: " << obj->value << std::endl;  // 通过指针访问 value 成员
    delete obj;                    // 释放内存
    return 0;
}

工作原理

-> 运算符的工作原理可以分解为两个步骤:

  1. 指针解引用:将指针转换为对象。
  2. 成员访问:访问对象的成员。

例如,obj->display(); 等价于 (*obj).display();

  • *obj:解引用指针 obj,得到它所指向的对象。
  • .display():访问对象的 display 方法。

等价形式

(*obj).display();  // 等价于 obj->display();
(*obj).value = 10; // 等价于 obj->value = 10;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值