【问题标题】:Problem with a parsing function (int to const char*)解析函数的问题(int 到 const char*)
【发布时间】:2021-08-01 16:44:05
【问题描述】:

我需要创建一个解析函数,所以我写了这个:

inline const char* parse(const int &arg)
{
     return std::to_string(arg).c_str();
}

看起来很合理——至少对我来说是这样——但是当我尝试用 std::cout 而不是整数值来查看这个函数的值时,我得到了一些随机的 ascii 字符。

所以我尝试更改函数,结果是这样的:

inline const char* parse(const int &arg)
{
     return (new std::string(std::to_string(arg)))->c_str();
}

它按预期工作,但我想知道的是为什么第一个功能案例不能正常工作。

另外,出现了一个次要问题(对于我来说可能是一个愚蠢的初学者) - 如果我动态创建 std::string,我应该使用 std::move 返回函数的值吗? return std::move((new std::string(std::to_string(arg)))->c_str());

【问题讨论】:

  • 返回 std::string 而不是 (dangling)const char*
  • 您在函数中创建的字符串在函数结束时死亡,因此您返回的指针无效。
  • 之后你可能需要一个const char*,但函数应该返回std::string,你仍然可以从结果中使用c_str()方法。
  • 为什么要回const char*?更广泛的背景是什么?
  • @czarson 然后按照@Jarod42 所说的做:返回一个字符串,然后使用c_str

标签: c++ c++11 move-semantics


【解决方案1】:
inline const char* parse(const int &arg)
{
     return std::to_string(arg).c_str();
}

函数parse 的本地新字符串是从std::to_string(arg) 创建的,您可以通过c_str 获得它的内部字符串。 c_str 当然会返回 const char *,但现在这会产生问题。该字符串仍然是函数的本地字符串,但是在函数结束时它被销毁后,返回的究竟是什么? c_str 只返回一个指向内部字符串的指针,它不会创建副本.因此,您有一个悬空指针:它指向已释放的内存。

inline const char* parse(const int &arg)
{
     return (new std::string(std::to_string(arg)))->c_str();
}

new 在堆上创建一个字符串。在前面的示例中,在堆栈上创建了一个字符串,该字符串在函数结束后被释放,但堆不以这种方式工作。您必须使用delete 手动删除内存。这产生了另一个问题:您返回 c_str 并且它可以工作,因为该字符串尚未被释放,但是您现在如何释放该字符串?事实上,你不能因为没有指向它的指针,所以你已经创建了内存泄漏。

您返回const char * 的原因是:

我需要返回 const char*,因为该函数只能用作另一个函数中的参数(参数的类型是 const char*)。

但您仍然可以返回 std::string 并在返回值上使用 c_str。以puts 为例:

#include <cstdio>
#include <string>

std::string parse(const int &arg)
{
    return std::to_string(arg);
}

int main()
{
    std::puts(parse(42).c_str());
    return 0;
}

【讨论】:

  • 返回std::move能解决内存泄漏问题吗?
  • @czarson 来自我对std::move 了解的(非常)少,我不认为如此,但我不能说。
【解决方案2】:

这在第一种情况下会调用未定义的行为。你创建了一个字符串对象,当函数返回时,它的生命周期就结束了,所以你返回的指针在那个时候也将是无效的。

在第二种情况下,你会造成内存泄漏,因为字符串对象永远不会被删除。

你可以做的是复制字符串,例如:

return strdup(str.c_str());

当然,调用者必须在完成后释放这个指针。所以主要的问题是为什么你不能返回字符串对象本身,这将是安全的方法。

std::string parse(const int &arg)
{
    return std::to_string(arg);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 2023-03-08
    • 2015-01-05
    • 1970-01-01
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多