对c++ 左值右值引用的一些体会

背景

在使用unordered_map创建的需要长期管理的容器时,发生了一些左右值返回的问题。
如:我不想通过

auto aaa = this->get_client(icp_server_name))
func(aaa)

想直接用如下,从而直接获取到容器中的对象,而不是用auto接收一个右值的临时对象

func(this->get_client(icp_server_name)))

因此就导致了将临时的右值对象传递到需要左值的函数func中。

解决方法

将func的形参改为常量引用形式,如:原本函数为

bool YSTaskManager::send_request(
typename rclcpp::Client::SharedPtr &client_,
const typename ServerType::Request::SharedPtr &request)

将其改为

bool YSTaskManager::send_request(
const typename rclcpp::Client::SharedPtr &client_,
const typename ServerType::Request::SharedPtr &request)

即可

gpt讲解

好的,关于 常量引用右值/左值 绑定的概念,涉及到 C++ 中的几个重要知识点:右值引用、左值引用、常量引用对象生命周期。下面我会逐步解释为什么将 client_ 参数修改为常量引用类型会有助于解决问题。

1. 引用的类型:左值引用与右值引用

  • 左值引用(Lvalue Reference):左值引用是指向“左值”的引用。左值是指可以取地址的对象,通常是有名字的对象(如变量、数组等)。

    • 语法:T&(例如:int&
  • 右值引用(Rvalue Reference):右值引用是指向“右值”的引用。右值是没有名字、通常是临时对象(例如:返回值、字面量、std::move 等)。

    • 语法:T&&(例如:int&&

2. 常量引用(const T&

常量引用是对对象的引用,但引用的对象不可被修改。常量引用可以绑定到 左值右值,这使得它在需要接受临时对象(右值)时非常有用。

  • 左值绑定常量引用:可以接受具有名称的对象。
  • 右值绑定常量引用:即使是临时对象(没有名称),也能通过常量引用绑定。
int x = 10;
const int& ref1 = x;  // 左值绑定
const int& ref2 = 20;  // 右值绑定

3. 为什么将 client_ 改为常量引用?

在你遇到的错误中,send_request 的参数是 rclcpp::Client<ServerType>::SharedPtr&,这是一个 非 const 左值引用。非 const 左值引用只能绑定到 左值(具有持久化生命周期的对象),而 右值(如临时对象)是不能绑定到非 const 左值引用的,因为右值在传递后会“消失”,无法继续引用。

std::shared_ptr 是一个智能指针,它的目标是管理动态分配的对象,其生命周期通常是由引用计数控制的。我们希望 send_request 函数能够接受既可能是已有客户端(左值),也可能是临时创建的客户端(右值)。

关键点:
  • 右值传递问题:如果你不修改为常量引用,右值(比如临时 SharedPtr)就无法绑定到非 const 左值引用上,因为它没有持久化的生命周期,不能保证在 send_request 结束时还有效。
  • 常量引用的优点const 使得 右值 也能被安全地传递到 send_request,因为常量引用允许绑定到临时对象,并且不会修改对象的内容。

4. 修复你的函数签名

修改 send_request 函数的签名,将 rclcpp::Client<ServerType>::SharedPtr& 改为 const rclcpp::Client<ServerType>::SharedPtr&,这样就可以接受左值和右值。

// 原来是:
bool send_request(rclcpp::Client<ServerType>::SharedPtr& client_, 
                  const typename ServerType::Request::SharedPtr& request);

// 修改为:
bool send_request(const rclcpp::Client<ServerType>::SharedPtr& client_,
                  const typename ServerType::Request::SharedPtr& request);
为什么修改?
  • 右值绑定:常量引用可以绑定临时对象(右值)。例如,this->get_client<ServerType>(service_name) 返回的是一个右值,它是一个临时对象。如果我们传递一个右值(临时对象)给 send_request,并且参数是非 const 左值引用,会导致编译错误。通过将参数修改为常量引用,可以避免这个问题。

  • 代码简洁:常量引用不会修改对象,并且允许接受临时对象。在这种情况下,SharedPtr 并不需要被修改,因此使用常量引用是合理的。

  • 生命周期管理std::shared_ptr 是一个智能指针,它负责对象的生命周期管理,通常不需要在函数内部修改或拷贝它。将其传递为常量引用可以避免不必要的拷贝,并且确保对象的生命周期由智能指针控制。

5. 总结

  • 常量引用const T&)是接受 左值右值 的通用方式。
  • 右值(临时对象)不能绑定到 const 左值引用 上,因此你需要使用 常量引用 来处理右值传递的问题。
  • 通过将 client_ 修改为 const rclcpp::Client<ServerType>::SharedPtr&,你可以接受临时对象,也可以接受已存在的客户端对象,从而使得函数调用更为灵活和安全。

这个修改不仅修复了编译错误,还使得代码更符合智能指针的使用习惯。如果你对这个问题还有其他疑问,或者需要进一步的帮助,请随时告诉我!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值