【问题标题】:C++ strange behavior with string's c_str() function字符串的 c_str() 函数的 C++ 奇怪行为
【发布时间】:2014-08-19 09:42:54
【问题描述】:

我正在将我的项目从 Visual Studio 06 移动到 2010。在这样做的同时,我在我的代码中观察到了这种行为。我有一个如下所示的 Get 字符串函数:

string GetTheStr() 
{ 
        return strSomeStdString; 
} 

然后还有另一个函数像这样调用上面的get函数:

const char* ptrStr = (char *)GetTheStr().c_str();

ptrStr指向的字符串的值为""

以上代码在 Visual Studio 06 中运行良好,但在 Visual Studio 2010 中运行不正常。

然后我尝试了几个实验:

std::string str = GetTheStr(); // -> value inside str displayed correctly
const char* PtrCStr = str.c_str(); // -> value pointed by PtrCStr displayed correctly
const char* PtrData = str.data(); // -> value pointed by PtrData displayed correctly
const char* ptr = (char *)GetTheStr().c_str(); // -> value pointed by ptr NOT displayed correctly

我想知道为什么最后一行不起作用。 谁能告诉我为什么上述行为发生在 Visual Studio 2010 而不是 Visual Studio 06?

提前致谢:)

【问题讨论】:

  • @MichaelAaronSafyan 这应该是一个答案。
  • 不需要(char *)演员
  • strSomeStdString 究竟从何而来?

标签: c++ stdstring


【解决方案1】:

在无效情况下发生的情况是 GetTheStr() 返回一个临时值,然后 c_str() 返回对其内部数据的引用,然后临时值超出范围,突然你有一个悬空的存储引用不再有效。当您将 GetTheStr() 的返回值分配给命名变量时,该变量仍然存在,并且其 c_str() 的结果仍然指向有效数据。

临时对象的生命周期因实现而异。我的理解是整个语句的临时生命(std::cout << GetTheStr().c_str() << endl; 在技术上对我的理解是有效的,因为lifteime 需要在整个语句中持续,但写得不好,因为它依赖于生命周期的一个非常微妙的方面);但是,根据我的理解,临时是否超出该声明到范围的末尾是由实现定义的。最后一段我可能会被嘲笑(尤其是那些对该主题有更精确知识的人),但简短的故事是,当需要延长对象的生命周期时,编写良好的代码应该更加明确;如果您需要保留对对象内部数据的引用,那么最好保证有一个命名变量引用该对象,以确保包含对象的生命周期超过其内部数据的使用生命周期。

【讨论】:

  • 语句cout << GetTheStr().c_str() << endl等价于operator<<(cout,GetTheStr().c_str()).operator<<(endl),从中可以看出,对于第一个operator<<的函数调用,指针的生命周期是有保证的,与指针的情况不同到临时保存并传递
  • @DmitryLedentsov,即使使用函数调用语法,也不是很明显它应该工作(即使它确实有效)。仍然存在对很快无效的数据的可怕引用。在另一个世界中,编程语言说 GetTheStr() 结果的生命周期在函数被调用之前结束是合乎逻辑的(尽管幸运的是事情并非如此)。我的防御性程序员总是假设最恶意、不兼容的编译器,并且总是将中间结果分配给命名变量。
  • 是的,你是对的,我假设太多了。我想我们都应该深入了解标准
【解决方案2】:

简单来说

std::string str = GetTheStr(); // -> this is a copy of strSomeStdString
const char* PtrCStr = str.c_str(); // -> str is still alive, ok
const char* PtrData = str.data(); // -> str is still alive, ok
const char*ptr = (char *)GetTheStr().c_str(); // -> pointer to a temporary, bad

使用str 的生命周期来保持数据“活跃”

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 2017-01-11
    • 2016-08-10
    相关资源
    最近更新 更多