连接字符串的意外行为

Posted

技术标签:

【中文标题】连接字符串的意外行为【英文标题】:Unexpected behavior concatenating string 【发布时间】:2022-01-06 04:06:19 【问题描述】:

我试图在 C++11 中连接两个字符串,但我经常遇到意外的行为。

首先,我有一个函数可以将任何类型转换为字符串:

template <class T>
static inline const char * toStr(T arg) 
    stringstream ss;
    ss << arg;
    return (ss.str()).c_str();

然后,我这样使用这个函数:

string measure_name;
for (unsigned long j = 0; j < 1280; j++) 
    measure_name = string("ADC_") + toStr(j);
    cout << measure_name << endl;

一切顺利,直到我达到 4 位数字 (> 999) : 我的变量measure_name 通常等于“ADC_ADC_”......它是随机发生的。我做了一些研究,并没有发现这种奇怪的行为。

请注意,如果 toStr 返回 string 而不是 const char *,则此问题已得到解决。

另外,如果我尝试打印返回值,我从来没有看到它等于“ADC_ADC_”,所以我相信真正的问题来自连接指令:

string measure_name;
for (unsigned long j = 0; j < 1280; j++) 
    const char* tmp = toStr(j);
    if (!strcmp(toStr(j), "ADC_ADC_"))
        cout << "bug" << endl; //never happens
    measure_name = string("ADC_") + tmp; //problem comes from here
    cout << measure_name << endl;

我只是想了解我在那里做错了什么......我知道我使用的是非常旧的 C++,但无论如何它应该可以工作。

感谢您的帮助。

【问题讨论】:

【参考方案1】:

这里

return (ss.str()).c_str();

您正在返回一个指向临时std::string 缓冲区的指针(从str() 返回)。函数返回的指针对调用者来说是无用的,因为它指向的std::string已经消失了。

指针只是一个指针。如果你想要一个字符串,返回一个std::string。如果您想返回 const char*,则需要将字符串存储在某处并管理其生命周期。

std::string 确实管理字符数组的生命周期,所以只需这样做:

template <class T>
static inline std::string toStr(T arg) 
    stringstream ss;
    ss << arg;
    return ss.str();

如果有人需要 char 的 c 数组,他们仍然可以调用 c_str(只要 std::string 仍然存在,就可以使用它)。


考虑使用std::to_string,而不是您的toStr

【讨论】:

@tony_merguez 你不明白哪一部分?什么让你困惑? c_str 返回一个指向存储在从str() 返回的std::string 中的字符数组的指针。当您尝试使用该指针时,此 std::string 不再存在 我知道std::string 管理生命周期,但我想了解(如果可能的话)为什么我正在做的事情适用于 3 位或更少的数字。 ( @tony_merguez 从您的toStr 返回的指针悬空。使用它总是错误的。这是未定义的行为。未定义的行为可能看起来有效,也可能无效,或者做一些奇怪的事情。 @tony_merguez:对这种差异的一种可能解释是“小字符串优化”。许多std::string 实现在内部以不同的方式存储小字符串和大字符串。您的实现很可能选择长度为 4 作为截止值,因为在该实现中,指针是 4 个字节。您的 3 位字符串加上终止 \0c_str() 将完全适合。它仍然是未定义的行为,但症状可能会有所不同,或者崩溃可能发生在不同的时间。

以上是关于连接字符串的意外行为的主要内容,如果未能解决你的问题,请参考以下文章

连接字符串的意外问题

Lint错误 - 意外的字符串连接

WCF 超时太快和“连接意外关闭”异常

C#中子字符串的意外行为[重复]

监听套接字意外死亡

C++ 字符连接与 std::string 行为。请解释一下