【问题标题】:Is this behaviour of std::quote bug?这是 std::quote 错误的行为吗?
【发布时间】:2021-09-06 00:28:36
【问题描述】:

我想用自定义类型做与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++ 为您提供了所有可能犯错和自取其辱的可能性。指导口号通常是“不要为你不需要的东西买单”。性能高于安全。正确使用它是你的工作。
  • auto q = std::string("text").c_str(); std::cout &lt;&lt; q &lt;&lt; '\n'; 会遇到同样的问题。临时对象消失了,任何指向其内容的东西都变得无效。

标签: c++ stl c++14 libc++


【解决方案1】:

这是意料之中的。或者更确切地说:这不会起作用。

来自cppreference

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

当在表达式中使用时

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

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

c) 最后将 delim 再次附加到 seq 上

返回值

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

并且“描述的 bahvior”是上面的:“当在表达式 out &lt;&lt; quoted(s, delim, escape) 中使用时,其中 out [...]”然后字符串 s 被输出到流中。当该字符串 s 不再存在时,您无法将其输出到流中。


实际上cppreferece上写的内容你也可以在标准中找到,只是稍微改写了一下,不幸的是没有添加很多澄清。来自标准[quoted.manip#2]

返回:一个未指定类型的对象,如果out是一个basic_ostream的实例,其成员类型char_type与charT相同,并且成员类型traits_type在第二种和第三种形式中与traits相同,则表达式out

请注意,它仅说明表达式 out &lt;&lt; quoted(s, delim, escape) 中发生的情况。这是您可以依赖的唯一用法。也许note 有助于澄清:

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

std::quoted 是一个 io 操纵器。它的返回值不打算用于任何事情,而是传递给流operator&lt;&lt;operator&gt;&gt;

【讨论】:

  • 我认为你的回答是正确的。我也认为它会从更清晰中受益更多。基本上,该标准规定std::quoteds 行为仅在用于具有std::ostream 实例out &lt;&lt; quoted(...) 的表达式中时指定。你确实这么说,但我认为是迂回的方式。最后,我觉得[quoted.manip]里的实际标准其实比这里的cppreference要清晰。
  • @AndyG 不确定如何更好地表达它,我只是添加了标准中的引用。缺少某些东西总是比相反的更难证明/解释
猜你喜欢
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多