【问题标题】:Improper use of c_strc_str 使用不当
【发布时间】:2014-07-15 04:38:43
【问题描述】:

我有一个方法定义如下:

const std::string returnStringMethod()
{
    std::string myString;

    // populate myString

    return myString;
}

现在,在调用者中,我正在做这样的事情:

const char * ptr = returnStringMethod().c_str(); 

正如我所见,这返回了一些我没想到的截断字符串。但是,以下工作正常:

std::string str = returnStringMethod();
const char * ptr = str.c_str();

有人可以帮我理解这里发生了什么吗? .

PS:我们每周构建一次代码。我上周提交代码时对此进行了测试,一切都很好。所以,我真的很想知道我在这里可能缺少什么。

谢谢, 帕万。

【问题讨论】:

  • "我们每周构建一次代码" => 可能跑题了,但为什么呢?有什么东西阻止你编译......只要有意义?
  • 不,我想说的是,当我上次在关闭更改之前处理此代码时,这并通过了所有测试。
  • 除非你真的知道你在做什么,否则不要复制c_str()返回的指针,而是直接在C-API调用中使用它。 c_str() 方法旨在用作适配器,这也是它的奇怪名称的原因。
  • 好点狼。 @Pavan:取消引用悬空指针是未定义的行为。所以如果你幸运的话它会坏掉,如果你不走运,它可能会毫无问题地工作。

标签: c++ pointers memory-management stdstring


【解决方案1】:

您正在返回一个(临时)副本,这就是您执行 c_str() 的地方。

当临时消失后,c_str()返回的char *就失效了。

【讨论】:

    【解决方案2】:

    第一个是未定义的行为,临时的returnStringMethod() 仅在尾随的; 之前有效,因此内部字符串(由c_str() 返回)被销毁,因此您只剩下一个悬空指针。

    第二个版本是有效的,因为str 将在其作用域结束时被销毁,并且其作用域与ptr 相同(至少在您的示例中)。

    例如,以下也是错误的:

    const char * ptr = NULL;
    {
        std::string str = returnStringMethod();
        ptr = str.c_str();
    }
    

    } 之后,ptr 不再有效。

    【讨论】:

    • 你能告诉我临时 returnStringMethod() 究竟是什么时候在 returnStringMethod().c_str() 中被销毁的吗?。
    • @Pavan 这是未定义的行为,在这种情况下,您实际上是在说“立即将其丢弃”。
    • @Pavan:有关定义,请参见 this question。一个好的经验法则是在创建它的语句执行后立即销毁临时对象。执行以下语句时,临时不再存在。
    【解决方案3】:

    returnStringMethod返回值是一个临时字符串,其生命周期与表达式本身绑定;这意味着您调用c_strstd::string 将在ptrconst char * ptr = returnStringMethod ().c_str () 中初始化后立即被破坏。

    这意味着ptr 的值已被初始化为指向不再可访问的内存。


    在后一种情况下,您将returnStringMethod 的返回值分配给std::string str,您将拥有一个生命周期绑定到当前范围的副本。因此,只要str 存在,将str.c_str () 的值分配给ptr 就有效。

    【讨论】:

      【解决方案4】:
      const char * ptr = returnStringMethod().c_str();
      

      在上面的行中,函数返回了一个临时字符串,该字符串很快就会超出范围。 (并调用析构函数并释放内存)

      在以后的版本中,您制作了字符串的本地副本,从而定义了行为。

      你也可以使用下面的

      const std::string &str = returnStringMethod();
      const char * ptr = str.c_str();
      

      使用 const 引用会延长临时变量的生命周期,直到引用在范围内并且不会有(显式)不需要的副本。

      【讨论】:

      • 你能告诉我函数返回的字符串何时超出范围吗?
      • 紧跟在line end 之后。但是如果你keep a reference,指针是可以安全使用的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-20
      • 1970-01-01
      • 1970-01-01
      • 2014-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多