11月13日晚
问题情景
问题发生在编写rpc项目的时候,项目已经编写完成。在测试的时候发现了这个问题。问题代码如下:
// 创建 MprpcController 对象
MprpcController *controller = new MprpcController();
// 发起rpc方法调用
stub.Login(controller, &request, &response, nullptr);
if (controller->Failed())
{
// 处理相应逻辑
}
else
{
// 处理相应逻辑
}
问题出现在上面代码的第7行,只要访问controller
的成员就发生段错误(这一点可以确定)。按道理来说这里不应该出现段错误,因为段错误一般是数组越界、访问了空指针或是访问了已经释放的内存。但是我使用gdb调试打印这里controller
的值,并不是nullptr
,那就只有可能是访问了已经释放的内存,又由于controller
的值并不为nullptr
,应该是原来存放controller
指向对象的内存又放了别的东西。但是我不知道为什么会发生这样的情况,我觉得按照逻辑来说这是不可能的,原因如下:
- 从创建
controller
起到第七行代码,中间只调用了一个成员函数,controller
作为该函数的参数被传了进去,但是传进去的是指针,Login
函数内部的形参指针,是controller
的拷贝,即使在Login
函数的作用域中销毁了该形参,仍然影响不到controller
所指向的对象。
所以我不理解这里为什么会发生段错误。gdb调式时有个奇怪的现象,我尝试使用p controller->m_failed
打印controller
的成员对象,输出结果告诉我他没有名为m_failed
的成员对象。这一切似乎都在证实上面的猜测。但是我不知道controller
所指对象究竟是怎么被释放的。
错误解决办法
解决方法很简单,既然可能的错误原因是访问了已被释放的内存,那么我就让controller
所指对象根本不可能被释放。就是使用new
申请一片堆内存,最后用delete
将controller
释放掉,只需做两行修改。代码如下:
// 创建 MprpcController 对象
MprpcController *controller = new MprpcController();
// 发起rpc方法调用
stub.Login(controller, &request, &response, nullptr);
if (controller->Failed())
{
std::cout << controller->ErrorText() << std::endl;
LOG_ERR("%s", controller->ErrorText().c_str());
}
else
{
if (0 != response.result().errcode())
std::cout << "Rpc login response error: " << response.result().errmsg() << std::endl;
std::cout << "Rpc login success: " << response.success() << std::endl;
}
delete controller;
求路过的大佬解答一下我的问题
11月14日上午
我想明白了
昨天晚上脑子抽抽儿了,我忽视了一个基础而又关键的问题。
MprpcController *controller;
像这样的语句只能声明一个指针,内存里不论是堆还是栈都没有实际的MprpcController
对象。还需要手动去创建一个对象,然后让controller
指向它。
这么简单的错误以后别再犯了🙏🙏🙏🙏🙏🙏🙏