左值右值、函数传参:
  1. 传值(按值传递) 如果函数的参数是通过按值传递的,传入一个右值时,编译器会生成一个临时对象,并将该临时对象复制或移动到函数内部的局部变量中。
  • 复制:对于不可移动的类型(例如基础类型 int),右值会被复制。
  • 移动:对于可以移动的类型(例如拥有移动构造函数的类),右值将会被移动,从而避免复制的开销。移动操作是一个高效的浅拷贝操作,将资源的所有权从右值转移到函数内部的局部变量中。
  1. 传引用(按引用传递)
    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_ptrstd::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 销毁时释放。
1
2
3
4
5
void process(std::unique_ptr<int>&& ptr) {
    std::cout << "Value: " << *ptr << std::endl;
}
std::unique_ptr<int> p1 = std::make_unique<int>(42);
process(std::move(p1));  // 使用 std::move 将所有权转移给 process 函数

std::unique_ptr 作为参数传入函数时:

  • 如果 unique_ptr 是左值并传递到需要按值接收 unique_ptr 的函数,会导致编译错误,因为 unique_ptr 不支持拷贝。
  • 按左值引用传递不会转移所有权,传入的 unique_ptr 仍保持有效。
  • 如果需要转移所有权,通常使用右值引用或者 std::move 将其显式地转换为右值。

之前把函数对象/仿函数当做是麻烦版本的lamada,看书里的用法才知道其灵活性。相当于一个方便管理变量的函数。