【问题标题】:Returning 'c_str' from a function从函数返回“c_str”
【发布时间】:2011-02-09 01:46:56
【问题描述】:

这是我在网上找到的一个小型图书馆:

const char* GetHandStateBrief(const PostFlopState* state)
{
    static std::ostringstream out;

    // ... rest of the function ...

    return out.str().c_str()
}

在我的代码中,我正在这样做:

const char *d = GetHandStateBrief(&post);
std::cout<< d << std::endl;

现在,起初d 包含垃圾。然后我意识到我从函数中获取的 C 字符串在函数返回时被销毁,因为std::ostringstream 是在堆栈上分配的。所以我补充说:

return strdup( out.str().c_str());

现在我可以从函数中获取我需要的文本了。

我有两个问题:

  1. 我理解正确吗?

  2. 我后来注意到outstd::ostringstream 类型)被分配了静态存储。这是否意味着该对象应该保留在内存中直到程序终止?如果是这样,那为什么不能访问字符串呢?

【问题讨论】:

    标签: c++ c c-strings c-str static-allocation


    【解决方案1】:

    strdup 在堆上分配字符串的副本,稍后您必须手动释放它(我认为是free())。如果可以选择,最好返回std::string

    out 的静态存储没有帮助,因为.str() 返回一个临时的std::string,在函数退出时被销毁。

    【讨论】:

      【解决方案2】:

      你说得对,out 是分配在数据段上的静态变量。但是out.str() 是在栈上临时分配的。因此,当您执行return out.str().c_str() 时,您将返回一个指向堆栈临时内部数据的指针。请注意,即使字符串不是堆栈变量,c_str 也“仅被授予保持不变,直到下一次调用字符串对象的非常量成员函数。”

      我认为你已经找到了一个合理的解决方法,假设你不能只返回一个字符串。

      【讨论】:

      • 嗯,“在堆上分配的静态变量” - 从未听说过这样的事情 :)
      • 好吧,字符串的字符数据确实与任何 std::string 一起存储在堆上,无论是静态的还是其他的。它是存储在数据段上的字符串描述符,就像其他具有全局生命周期的变量一样。
      【解决方案3】:

      strdup() 返回一个指向堆上内存的 char* 指针。完成后你需要 free() 它,但是是的,这会起作用。

      在这种情况下,静态局部变量 std::ostringstream out 没有任何意义,除非返回的 std::string 也是静态的,而您的观察表明它是不正确的。

      【讨论】:

        【解决方案4】:

        GetHandStateBrief 中,变量out 不需要是静态的。您需要一个明确的static string 来替换在您对out.str() 的原始调用中创建的临时:

        static std::string outStr;
        std::ostringstream out;
        ... rest of function ...
        outStr = out.str();
        return outStr.c_str();
        

        【讨论】:

        • 这是有风险的。返回的char* 在后续调用GetHandStateBrief 后不保证有效。
        • 确实,每次调用GetHandStateBrief 都会使前一次调用返回的指针无效。不过,风险取决于上下文。
        • 我也没有反对意见,但是“函数中的静态变量,因此我们可以返回指针而不是仅仅返回对象”是 C++ 中众所周知的反模式。请参阅 Scott Meyer 的 Effective C++ 第 2 版,第 23 条。
        • 我认为这并不比原始代码差(除了这个有效)。 C++ 程序中的 strdup 不一定更好。
        • 都是真的 - 但我会留下它,因为这成功地完成了他试图做的事情。当不共享 CRT 时,我不得不在 dll 中使用类似的反模式。 OTOH,我同意如果可以返回对象,则不应该这样做。
        猜你喜欢
        • 2013-10-15
        • 2017-03-26
        • 2021-06-30
        • 1970-01-01
        • 2018-11-22
        • 1970-01-01
        • 2019-04-29
        • 2013-11-14
        • 1970-01-01
        相关资源
        最近更新 更多