对 C++ 左值、右值、智能指针的思考
Contents
左值右值、函数传参:
- 传值(按值传递) 如果函数的参数是通过按值传递的,传入一个右值时,编译器会生成一个临时对象,并将该临时对象复制或移动到函数内部的局部变量中。
- 复制:对于不可移动的类型(例如基础类型 int),右值会被复制。
- 移动:对于可以移动的类型(例如拥有移动构造函数的类),右值将会被移动,从而避免复制的开销。移动操作是一个高效的浅拷贝操作,将资源的所有权从右值转移到函数内部的局部变量中。
- 传引用(按引用传递)
2.1 传左值引用void foo(const std::string& s);
当函数接受一个const 左值引用时,如果传入一个右值,编译器会生成一个临时对象并将它绑定到左值引用上。这时不会发生复制或移动,函数内部会直接使用右值的临时对象。这个临时对象的生命周期会被延长到函数结束。 2.2 传右值引用void foo(std::string&& s);
当函数接受一个右值引用时,右值引用参数可以直接绑定到右值,因此不会发生复制。通常情况下,右值引用用于转移资源的所有权,函数内部可以自由地操作该右值引用的内存内容。
std::move 与 智能指针
std::move()
本身并不会移动数据,它只是将对象的左值强制转换为右值引用,从而允许对象使用移动构造函数或移动赋值运算符。实际的“移动”行为是在这些函数中实现的。
std::move() 可以传入普通指针(如 int*)。传入指针时并不会产生任何有实际意义的“移动”行为,由于指针只是指向某个内存地址的变量(而不负责管理资源),所以“移动”一个指针只是简单地转移其地址值,并没有实际涉及资源的所有权转移。
当
std::move
传入智能指针(如std::unique_ptr
或std::shared_ptr
)时,与传入普通指针相比,它会产生实际的资源转移,这是智能指针的移动语义带来的结果。std::unique_ptr
是独占所有权的智能指针,意味着它独自管理动态分配的对象。不能复制std::unique_ptr
,但可以通过移动将所有权转移给另一个std::unique_ptr
。被移动的std::unique_ptr
会变为nullptr
。std::move
+std::shared_ptr
:将std::shared_ptr
的引用计数和所有权从一个对象转移到另一个。被移动的shared_ptr
变为nullptr
,但原来共享的资源只会在最后一个shared_ptr
销毁时释放。
|
|
当 std::unique_ptr
作为参数传入函数时:
- 如果
unique_ptr
是左值并传递到需要按值接收 unique_ptr 的函数,会导致编译错误,因为unique_ptr
不支持拷贝。 - 按左值引用传递不会转移所有权,传入的
unique_ptr
仍保持有效。 - 如果需要转移所有权,通常使用右值引用或者
std::move
将其显式地转换为右值。
之前把函数对象/仿函数当做是麻烦版本的lamada,看书里的用法才知道其灵活性。相当于一个方便管理变量的函数。