C++ 访问字符串::c_str()的结果时发生valgrind内存访问错误

C++ 访问字符串::c_str()的结果时发生valgrind内存访问错误,c++,pointers,valgrind,stdstring,C++,Pointers,Valgrind,Stdstring,所以,当我遇到最奇怪的内存问题时,我正在编写一些网络代码,我无法正确地找出这里可能发生的事情。我想知道在c_str()中是否有某种我没有正确观察到的暗示 下面是包含错误的代码。(还有一个释放错误,但我将此函数作为一个宠物项目) 那么就没有内存错误了。我不太明白为什么 另一件需要注意的事情是,如果我尝试用const char*变量编译版本,而不是用char*编译,您会得到一个警告,该变量应该是常量 这里发生了什么?由c_str返回的缓冲区只有在关联的std::string对象存在时才有效。这里呢

所以,当我遇到最奇怪的内存问题时,我正在编写一些网络代码,我无法正确地找出这里可能发生的事情。我想知道在
c_str()
中是否有某种我没有正确观察到的暗示

下面是包含错误的代码。(还有一个释放错误,但我将此函数作为一个宠物项目)

那么就没有内存错误了。我不太明白为什么

另一件需要注意的事情是,如果我尝试用
const char*
变量编译版本,而不是用
char*
编译,您会得到一个警告,该变量应该是常量


这里发生了什么?

c_str
返回的缓冲区只有在关联的
std::string
对象存在时才有效。这里呢

const char* port_num = (std::to_string(port)).c_str();
创建一个临时字符串对象,获取其缓冲区地址,然后在完整表达式结束时终止。使用悬空指针会导致内存错误

如果希望使用临时的
std::string
,则必须在使用缓冲区的完整表达式期间创建它:

int res = getaddrinfo(nullptr, std::to_string(port).c_str(), &hints, &result)

With
const char*port_num=(std::to_string(port)).c_str()
,您正在创建一个类型为
std::string
的临时对象,该对象将与使用它的表达式一样长。因此,
.c_str()
将指向在语句之后立即释放的内存

把它分成两行:

auto portStr = std::to_string(port);
const char* port_num = portStr.c_str();

因此,
portStr
-对象将一直存在到函数结束,您可以使用
.c_str
-调用的结果直到函数结束(除非您在两者之间更改
protStr

我更喜欢Stephan Lechner的建议,因为我的编码哲学(以及我教给人们的东西)is:每行做一件事,除非另有必要。它不会改变编译后的输出,而且更容易读取IMHO。有人可能会说,它更程序化,功能更少,但这就是。@einpoklum——另一种哲学是不要说出不重要和短暂的事情。而“一行一行”的方法在任何C++程序中都失败得很快。获取
提示
结果
的地址也与此不一致。大多数人,包括我自己,在这两者之间做一些事情是有原因的。不管怎样,这既不在这里也不在那里。我试图澄清的是生命问题,我没有说过,除非另有必要,而且经常是必要的,特别是在C++中…关于命名瞬变,你确实有一个观点,但是:1。使用参数名命名即将成为函数参数的对象并不坏,看看C/C++函数如何不使用命名参数赋值进行调用。2.瞬变是在命名后立即使用的,因此您很容易忘记名称3。与其含糊其辞,不如过于冗长。4.随着时间的推移,我发现比我预期的更多的东西可以被合理地命名。我感谢你提供了一个(几乎)最小的、完整的、可验证的例子,并亲自尝试。要是所有的新手用户都这么做就好了!
const char* port_num = (std::to_string(port)).c_str();
int res = getaddrinfo(nullptr, std::to_string(port).c_str(), &hints, &result)
auto portStr = std::to_string(port);
const char* port_num = portStr.c_str();