0

我从朋友那里得到了这个问题

#include <string>
#include <vector>
#include <iostream>

void riddle(std::string input)
{
    auto strings = std::vector<std::string>{};
    strings.push_back(input);
    auto raw = strings[0].c_str();

    strings.emplace_back("dummy");

    std::cout << raw << "\n";
}

int main()
{
    riddle("Hello world of!"); // Why does this print garbage?
    //riddle("Always look at the bright side of life!"); // And why doesn't this?

    std::cin.get();
}

我的第一个观察是,当传入的单词数超过 3 个单词riddle()时,该函数不会产生垃圾。input我仍在试图了解为什么它在第一种情况下失败,而不是在第二种情况下。不管怎样,我觉得分享这个很有趣。

4

2 回答 2

3

这是未定义的行为 (UB),这意味着任何事情都可能发生,包括代码工作。它是 UB,因为它emplace_back使指向向量中对象的所有指针无效。发生这种情况是因为向量可能会被重新分配(显然是这样)。

由于短字符串优化 (sso),UB 的第一种情况“不起作用”。由于sso,原始指针指向向量直接分配的内存,重新分配后丢失。

UB 的第二种情况“有效”,因为字符串文本对于 SSO 来说太长并且驻留在独立的内存块上。在调整大小期间,字符串对象被移动,将文本内存块的所有权移动到新创建的字符串对象。由于内存块只是更改所有权,它在emplace_back.

于 2019-02-21T04:37:38.250 回答
2

std::string::c_str()

返回的指针可能会因进一步调用修改对象的其他成员函数而失效。


std::vector::emplace_back

如果发生重新分配,所有包含的元素都会被修改。


由于无法知道vector调用时是否会发生重新分配,因此emplace_back您必须假设后续使用较早的返回值 fromstring::c_str()会导致未定义的行为。

由于未定义的行为是 - 未定义的 - 任何事情都可能发生。因此,您的代码可能看起来可以工作,也可能看起来失败。无论哪种方式都是错误的。

于 2019-02-21T05:03:35.240 回答