Chapter3 Move Semantics in Classes

C++移动语义详解
本文深入探讨C++11引入的移动语义,包括移动构造函数和移动赋值运算符的自动生成条件及应用场景。此外,还介绍了如何正确实现特殊移动成员函数,并讨论了移动语义对默认构造函数、拷贝构造函数等的影响。

1. Move Semantics in Ordinary Classes

①C++11之后,编译器会为简单的类生成 移动构造函数 和 移动赋值运算符
(就像生成的默认构造函数和默认赋值运算符)
什么时候会使用移动构造

  1. 当返回一个局部变量(return local obj by value)
  2. 按值传递一个无名对象
  3. 传递一个临时对象(例如 函数的返回值)
  4. 被std::move 标记的对象

③测试代码

一个简单的类 只有构造函数和一个重载的运算符

class Test
{
public:
     Test(const std::string& Temp) : str{Temp} {};
     

     friend ostream& operator<<(ostream& os, const Test& Temp)
     {
          os << Temp.str << endl;
          return os;
     }

private:
     std::string str;
};
int main()
{
     Test a("12345678910111213");
     cout <<"a   " << a << endl;

     cout << "***************" << endl;

     Test b = a;
     cout << "a   " << a << endl;
     cout << "b   " << b << endl;

     cout << "***************" << endl;

     Test c = std::move(a);
     cout << "a   " << a << endl;
     cout << "b   " << b << endl;
     cout << "c   " << c << endl;


     return 0;
}

在这里插入图片描述
我们可以看到 a的值已经被move给了c了

Test d = {std::move(b)};
     cout << "a   " << a << endl;
     cout << "b   " << b << endl;
     cout << "c   " << c << endl;
     cout << "d   " << d << endl;

我们可以看到 大括号初始化和赋值初始化中使用std::move确实被移动了

2.什么时候编译器不会自动生成这两个函数呢?

编译器得保证它自动生成的函数是正确的,符合用户需求的,所以编译器会受到一些限制。

①当类中有拷贝构造函数的时候
我们以前知道,对一个对象使用std::move,当该类中的构造函数没有存在右值引用的形参的时候X&&,他便会去找形参是const X&的构造函数
②当类中有拷贝赋值运算符
③其他的移动操作
④析构函数
基类有个虚的析构函数,但是子类没有析构函数,子类会生成这两个函数

/*****************************************************/
当发生上面情况的时候,那么编译器不会为我们生成移动函数了,所以我们需要注意
①可能会调用拷贝函数,得到的是我们不期望的结果
比如直接拷贝指针 进行了浅拷贝
②类的成员对值有要求
③对象没有默认的构造状态

3.Implementing Special Copy/Move Member Functions

// move constructor (move all members):
Customer(Customer&& cust)
: name{std::move(cust.name)}, values{std::move(cust.values)} 
{
	std::cout << "MOVE " << name << \n;
}
// move assignment (move all members):
Customer& operator= (Customer&& cust) 
{
	std::cout << "MOVEASSIGN " << cust.name << \n;
	if (this != &cust) 
	{ // move assignment to itself?
		name = std::move(cust.name);
		values = std::move(cust.values);
	}
	return *this; 
}

4. Rules for Special Member Functions

在这里插入图片描述
① 如果用户没有自定义构造函数,那么就会有默认构造函数
②拷贝成员函数 和析构函数 会禁止生成默认的移动成员函数
③move成员函数 会禁止生成默认的 copy成员函数

Deleting Moving Makes No Sense

class Person {
public:
...
// NO copy constructor declared
// move constructor/assignment declared as deleted:
Person(Person&&) = delete;
Person& operator=(Person&&) = delete;
...
};

你禁用了move,但是当类中声明了move成员函数,copy成员函数也被禁用了!

Person p{"Tina", "Fox"};
coll.push_back(p); // ERROR: copying disabled
coll.push_back(std::move(p)); // ERROR: moving disabled

/***************************************************/
Disabling Move Semantics

class Customer {
...
public:
...
Customer(Customer&&) = delete; // OOPS: does disable move calls
Customer& operator=(Customer&&) = delete; // OOPS: does disable move calls
};

这虽然是可以禁止移动语意,但是通常不是合适的做法

class Customer {
...
public:
...
Customer(const Customer&) = default; // disable move semantics
Customer& operator=(const Customer&) = default; // disable move semantics
};

上面是通常的做法
/***********************************************************/
Moving for Members with Disabled Move Semantics

class Customer {
...
public:
...
Customer(const Customer&) = default; // copying calls enabled
Customer& operator=(const Customer&) = default; // copying calls enabled
Customer(Customer&&) = delete; // moving calls disabled
Customer& operator=(Customer&&) = delete; // moving calls disabled
};
class Invoice
 {
std::string id;
Customer cust;
public:
... // no special member functions
};
Invoice i;
Invoice i1{std::move(i)}; // OK, moves id, copies cust

默认生成的拷贝函数和移动函数,会根据成员是否能移动或能拷贝做出不同的行为

5.Exact Rules for Generated Special Member Functions

我们有如下的派生类

class MyClass : public Base
{
private:
MyType value;
...
};

/************************************************/
Copy Constructor
拷贝构造函数自动生成的条件,是在没有用户没有自定义移动构造函数
和 移动赋值运算符的时候

通常像下面这样,基类的构造函数总是先执行

MyClass(const MyClass& obj)
: Base{obj}, value{obj.value}
{

}

/**********************************************/
Move Constructor
move构造函数 自动生成的条件
用户没有自定义拷贝构造函数,拷贝赋值运算符,移动赋值运算符,析构函数

通常像下面这样,总是保证基类的先被移动构造,如果一个类不能被移动但是能够被拷贝的话,那么就用拷贝代替移动

MyClass(MyClass&& obj)
: Base{std::move(obj)}, value{std::move(obj.value)} {
}

/**********************************************/
Copy Assignment Operator
拷贝赋值运算符 自动生成的条件
用户没有自定义移动构造函数 和 移动赋值运算符

MyClass& operator= (const MyClass& obj) {
Base::operator=(obj); // - perform assignments for base class members
value = obj.value; // - assign new members
return *this; }

生成的拷贝赋值运算符 总是保证基类的成员先被赋值

/**********************************************/
Move Assignment Operator
move赋值运算符生成的条件
用户没有自定义 拷贝构造函数 拷贝赋值运算符 移动构造函数 析构函数

MyClass& operator= (MyClass&& obj) {
Base::operator=(std::move(obj)); 
// - perform move assignments for base class members
value = std::move(obj.value); // - move assign new members
return *this; }

生成的移动赋值运算符,总是保证基类的成员先被移动,要是不能被移动赋值但是可以被拷贝赋值,那就用拷贝赋值代替

<think>好的,我需要帮助用户下载Habitat Matterport 3D Semantics数据集。首先,我得确认用户提到的数据集的具体名称和来源。根据用户提供的引用,Habitat-Matterport 3D数据集(HM3D)在GitCode上有镜像仓库,项目地址是https://gitcode.com/gh_mirrors/ha/habitat-matterport3d-dataset[^1]。用户可能想从这里获取数据集。 接下来,我应该检查官方下载步骤。通常,这样的数据集可能需要通过申请或同意条款来获取。用户可能需要访问官方网站或存储库,按照指示操作。例如,可能需要填写表格或使用命令行工具下载。 另外,引用中提到的其他数据集如Matterport3D和Gibson[^2]可能相关,但用户明确需要的是HM3D Semantics。需要确保提供的链接和步骤是针对语义版本的,而不仅仅是几何数据。 用户可能遇到的问题包括找到正确的下载页面、处理许可协议或使用下载工具如wget。需要分步骤说明,包括访问官网、申请访问、下载链接获取以及实际下载命令。 最后,要提醒用户注意数据集的使用条款和可能的文件大小,确保他们有足够的存储空间和稳定的网络连接。同时,如果下载过程中遇到问题,建议查阅官方文档或社区支持。</think>### 下载 Habitat Matterport 3D Semantics 数据集教程 #### 步骤 1:访问官方资源页面 1. **官方项目地址**: Habitat-Matterport 3D 数据集(HM3D)的镜像仓库位于 GitCode,可通过以下链接访问: [https://gitcode.com/gh_mirrors/ha/habitat-matterport3d-dataset](https://gitcode.com/gh_mirrors/ha/habitat-matterport3d-dataset) 此处提供数据集的文档和下载说明。 2. **语义数据集分支**: HM3D Semantics 是 HM3D 的扩展版本,包含语义标注信息。需从 Matterport3D 官网申请原始数据,并参考 Habitat-Sim 的集成文档。 #### 步骤 2:申请 Matterport3D 数据访问权限 1. **访问 Matterport3D 官网**: 前往 [Matterport3D 数据集页面](https://niessner.github.io/Matterport/) 注册账号并签署数据使用协议。 *注意:需提供机构邮箱(如.edu 或公司域名)以通过审核。* 2. **获取下载链接**: 审核通过后,会收到包含数据下载链接和密钥的邮件。 #### 步骤 3:下载与集成到 Habitat 1. **通过官方脚本下载**: Habitat 团队提供了自动化下载工具。安装 `habitat-lab` 库后,运行以下命令: ```bash python -m habitat_sim.utils.datasets_download --uids hm3d_semantics ``` 2. **手动下载(可选)**: 若脚本失效,可从邮件中的链接直接下载文件(约 150GB),解压后按文档放置到 `habitat-lab/data` 目录。 #### 步骤 4:验证数据 使用 Habitat-Sim 的示例代码加载场景,检查语义标注是否生效: ```python import habitat_sim sim = habitat_sim.Simulator(config=habitat_sim.Configuration( scene="data/scene_datasets/hm3d_semantics/00000-vLpv2VX547B/vLpv2VX547B.semantic.glb" )) print("场景语义层数:", sim.semantic_scene.categories) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值