C++ 11 move

关于c++ 11 中的move

move语义的主要作用是将一个对象的所有权转移到另外一个对象(对基本数据类型也是支持的,不过似乎并无效率的提高)

无论是The C++ Standard Library: A Tutorial and Reference提到的,还是网上的说法,一直声明改语义的主要作用是为了提高赋值的效率

而且经过验证的确如此,那么下列的代码运行结果很奇怪:


class TTT
{
	int i;

};

int main()
{
	vector<TTT> v;
	clock_t beg, end;
	int test_size = 10000;
	cout << "vector------------------" << endl;
	beg = clock();
	for (int i = 0; i < test_size; i++)
		v.push_back(TTT());
	end = clock();
	cout << "without move:";
	cout << end - beg << endl;
	v.clear();
	beg = clock();
	for (int i = 0; i < test_size; i++)
		v.push_back(std::move(TTT()));
	end = clock();
	cout << "with move:";
	cout << end - beg << endl;

	cout << "list---------------------" << endl;
	list<TTT> l;
	beg = clock();
	for (int i = 0; i < test_size; i++)
		l.push_back(TTT());
	end = clock();
	cout << "without move";
	cout << end - beg << endl;

	l.clear();
	beg = clock();
	for (int i = 0; i < test_size; i++)
		l.push_back(std::move(TTT()));
	end = clock();
	cout << "with move";
	cout << end - beg << endl;
	return 0;
}

其中一次的输出结果是:

vector------------------
without move:16
with move:7
list---------------------
without move30
with move27

对结果疑惑的主要原因是如果是转移对象的拥有权的话,对于vector这种线性存储的是如何做到的,难道其实现方式已经不是简单的物理上的顺序存储了?

刚刚看到那些新语法,多使用验证了

C++11 中,`std::move` 是一个非常重要的工具函数,它定义在 `<utility>` 头文件中,主要用于触发移动语义。其核心用途是将一个左值转换为右值引用,从而允许调用移动构造函数或移动赋值运算符,避免不必要的拷贝操作,提高程序性能。 ### `std::move` 的主要用途 1. **触发移动语义** `std::move` 的主要作用是将一个对象转换为右值引用,从而允许编译器选择移动构造函数或移动赋值运算符[^2]。这种转换并不会真正移动对象的内容,而是为移动操作做好准备。例如: ```cpp std::string str = "Hello"; std::vector<std::string> vec; vec.push_back(std::move(str)); // 将 str 移动到 vec 中 ``` 在这个例子中,`str` 被转换为右值引用,从而调用 `std::string` 的移动构造函数,而不是拷贝构造函数。 2. **避免不必要的拷贝** 在某些情况下,如果直接传递对象可能会导致拷贝构造函数被调用,而使用 `std::move` 可以避免这种不必要的拷贝操作。例如,在函数返回值中使用 `std::move` 来避免拷贝构造函数的调用[^3]: ```cpp std::string createString() { std::string result = "Very large string"; return std::move(result); // 避免拷贝构造函数 } ``` 3. **与完美转发结合使用** `std::move` 可以与 `std::forward` 结合使用,实现完美转发。完美转发是指在模板函数中将参数原封不动地传递给另一个函数,保留其左值或右值属性。例如: ```cpp template<typename T> void wrapper(T&& arg) { someFunction(std::forward<T>(arg)); // 完美转发 } ``` 在某些情况下,如果明确知道参数应该被移动,则可以使用 `std::move` 来强制转换为右值引用[^1]。 4. **用于资源管理** 在资源管理中,`std::move` 可以用于将资源从一个对象转移到另一个对象。例如,在 `std::unique_ptr` 中,由于不能拷贝,只能通过 `std::move` 来转移所有权: ```cpp std::unique_ptr<int> ptr1(new int(10)); std::unique_ptr<int> ptr2 = std::move(ptr1); // 转移所有权 ``` 5. **在容器中使用 `std::move`** 在标准库容器中(如 `std::vector`、`std::map` 等),使用 `std::move` 可以避免不必要的拷贝操作。例如: ```cpp std::vector<std::string> vec; std::string str = "Large string"; vec.push_back(std::move(str)); // 移动而不是拷贝 ``` 6. **与 `std::move_if_noexcept` 结合使用** 在某些情况下,为了避免异常抛出,可以使用 `std::move_if_noexcept`。它会在移动构造函数或移动赋值运算符不会抛出异常时才使用移动语义,否则使用拷贝语义[^1]: ```cpp std::vector<MyClass> vec; MyClass obj; vec.push_back(std::move_if_noexcept(obj)); ``` ### `std::move` 的实现原理 `std::move` 的实现本质上是一个 `static_cast`,将传入的对象转换为右值引用。其定义如下[^4]: ```cpp template <typename T> typename remove_reference<T>::type&& move(T&& t) noexcept { return static_cast<typename remove_reference<T>::type&&>(t); } ``` 通过 `std::remove_reference` 去除引用类型,再将其转换为右值引用类型。这种方式确保了无论传入的是左值还是右值,都可以被转换为右值引用。 ### 注意事项 - `std::move` 并不会真正移动对象的内容,它只是将对象标记为可以被移动的状态,实际的移动操作由接收对象的函数或容器完成[^3]。 - 使用 `std::move` 后,原对象虽然仍然存在,但其状态是未定义的,不应再使用它。 - 不要滥用 `std::move`,只有在确实需要移动语义时才使用,否则可能导致不必要的性能损失。 ### 示例代码 以下是一个使用 `std::move` 的完整示例: ```cpp #include <iostream> #include <utility> #include <vector> class MyString { public: char* data; MyString(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } MyString(const MyString& other) { data = new char[strlen(other.data) + 1]; strcpy(data, other.data); std::cout << "Copy constructor\n"; } MyString(MyString&& other) noexcept { data = other.data; other.data = nullptr; std::cout << "Move constructor\n"; } ~MyString() { delete[] data; } }; int main() { MyString str("Hello"); std::vector<MyString> vec; vec.push_back(std::move(str)); // 调用移动构造函数 return 0; } ``` 输出结果: ``` Move constructor ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值