这是 std::quote bug 的行为吗?

问题描述 投票:0回答:2

我想用自定义类型做与

std::quote
相同的事情,但我想错过使用这种带有临时右值的API。经过一番
std::quoted
的叮叮,我发现了以下问题:

为了高效

std::quoted
强制存储const引用或指针以避免源对象的深拷贝,但是没有机制可以避免存储引用的结果。如果我们存储它,然后删除源对象,最后将我们尝试访问已删除的引用或指针的存储结果流式传输。

下面的例子试图说明这个问题:

#include <string>
#include <iostream>
#include <iomanip>

class String
{
public:
    explicit String(const std::string & s) : _s(s) {std::cout << "String\n";}
    ~String() { std::cout << "~String\n"; _s = "ERROR TRY ACCESS DELETED STRING";}
    const std::string & getS() const {return _s;}
private:
    std::string _s;
};

int main()
{
    std::cout << std::quoted(String("test").getS()) << '\n';
    std::cout << '\n';

    auto q = std::quoted(String("test").getS());
    std::cout << q << '\n';
    return 0;
}

此示例打印:

String
"test"
~String

String
~String
"p DELETED STRING"

我们可以在 gcc(trunk) 和 clang(trunk) 中看到同样的问题。

c++ stl c++14 libc++
2个回答
4
投票

这是可以预料到的。或者更确切地说:这预计不会起作用。

来自cppreference

允许插入和提取带引号的字符串,例如 在 CSV 或 XML 中找到。

用于表达式 out 时 << quoted(s, delim, escape), where out is an output stream with char_type equal to CharT and, for overloads 2-4, traits_type equal to Traits, behaves as a FormattedOutputFunction, which inserts into out a sequence of characters seq constructed as follows:

a) 首先,将字符 delim 添加到序列中

b) 然后 s 中的每个字符,除非要输出的下一个字符等于 delim 或等于 escape(由流的 Traits_type::eq 确定),然后首先附加 escape 的额外副本

c) 最后,delim 再次追加到 seq 中

还有

返回值

返回未指定类型的对象,使得所描述的行为 发生了。

“描述的行为”如上:“当在表达式

out << quoted(s, delim, escape)
中使用时,out [...]”,则字符串
s
被输出到流中。当该字符串
s
不再存在时,您无法将其输出到流。


实际上 cppreferece 上写的内容也可以在 stadnard 中找到,只是稍微改写了,不幸的是没有添加大量说明。来自标准 [quoted.manip#2]:

返回:未指定类型的对象,如果 out 是 basic_ostream 的实例,其成员类型 char_type 与 charT 相同,且成员类型 Traits_type (在第二种和第三种形式中与 Traits 相同),则表达式 out << quoted(s, delim, escape) behaves as a formatted output function of out. This forms a character sequence seq, initially consisting of the following elements: [...]

请注意,它仅说明表达式中发生的情况

out << quoted(s, delim, escape)
。这是您唯一可以信赖的用法。也许注释有助于澄清:

[注1:带引号的操纵器提供字符串插入和提取 带引号的字符串(例如 XML 和 CSV 格式)。引 操纵器对于确保字符串的内容非常有用 如果插入然后通过以下方式提取,嵌入的空格将保持不变 流 I/O。 — 尾注]

std::quoted
是一个io操纵器。它的返回值并不用于任何用途,而是传递给流
operator<<
operator>>


0
投票

您可以将以下函数添加到您的代码中并使用它:

static auto quote_string(std::string_view s) {
    std::ostringstream x;
    x << std::quoted(s);
    return x.str();
}
© www.soinside.com 2019 - 2024. All rights reserved.