C++11 进阶:右值引用、移动语义详解与 Lambda 简介
承接上一节的内容,我们继续深入 C++11 的核心特性。本节重点探讨右值引用和移动语义在实际传参中的性能优化,并简要引入 Lambda 表达式。
右值引用在传参中的提效
查看 STL 文档可以发现,C++11 之后,容器的 push_back 和 insert 系列接口都增加了右值引用版本。这背后的逻辑非常直观:
- 左值实参:容器内部调用拷贝构造函数,将对象完整拷贝到容器空间。
- 右值实参:容器内部调用移动构造函数,直接将资源转移给容器空间的对象,避免不必要的深拷贝开销。
为了更清晰地理解这一机制,我们可以回顾之前模拟实现的 list 容器,为其增加支持右值引用参数的 push_back 和 insert 版本。
标准库行为演示
int main() {
std::list<std::string> lt;
std::string s1("111111111111111111111");
// 左值 push_back -> 调用拷贝构造
lt.push_back(s1);
// 临时对象 (右值) push_back -> 调用移动构造
lt.push_back(std::string("22222222222222222222222222222"));
// 字符串字面量 (右值) push_back -> 调用移动构造
lt.push_back("3333333333333333333333333333");
// 显式 move 左值为右值 -> 调用移动构造
lt.push_back(std::move(s1));
return 0;
}
运行结果会显示不同的构造过程:左值触发拷贝构造,而右值(包括字面量和 std::move 后的对象)则触发移动构造。这里还有一个 emplace 系列的接口,涉及可变参数模板,我们将在后续章节详细讲解。
自定义 List 实现细节
下面是自己实现 List 的右值版本 push_back。注意右值在层层传递时属性的变化,必须使用 std::move 保持其右值属性,才能正确调用移动构造函数。
// List.h
namespace bit {
template<class >
{
ListNode<T>* _next;
ListNode<T>* _prev;
T _data;
( T& data = ()) :_next(), _prev(), _data(data) {}
(T&& data) :_next(), _prev(), _data(std::(data)) {}
};
< , , >
{
ListNode<T> Node;
ListIterator<T, Ref, Ptr> Self;
Node* _node;
(Node* node) :_node(node) {}
Self& ++() { _node = _node->_next; *; }
Ref *() { _node->_data; }
!=( Self& it) { _node != it._node; }
};
< >
{
ListNode<T> Node;
:
ListIterator<T, T&, T*> iterator;
ListIterator<T, T&, T*> const_iterator;
{ (_head->_next); }
{ (_head); }
{
_head = ();
_head->_next = _head;
_head->_prev = _head;
}
() { (); }
{ ((), x); }
{ ((), std::(x)); }
{
Node* cur = pos._node;
Node* newnode = (x);
Node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
(newnode);
}
{
Node* cur = pos._node;
Node* newnode = (std::(x));
Node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
(newnode);
}
:
Node* _head;
};
}


