我想用自定义类型做与
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) 中看到同样的问题。
这是可以预料到的。或者更确切地说:这预计不会起作用。
来自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>>
。
您可以将以下函数添加到您的代码中并使用它:
static auto quote_string(std::string_view s) {
std::ostringstream x;
x << std::quoted(s);
return x.str();
}