std::quote 的这种行为是错误吗?

Is this behaviour of std::quote bug?

我想用自定义类型做与 std::quote 相同的事情,但我想错过使用这种具有临时右值的 API。在使用 std::quoted 进行了一番调试后,我发现了以下问题:

为了高效std::quoted强制存储常量引用或指针以避免对源对象进行深拷贝,但没有避免存储引用结果的机制。如果我们存储它,然后删除源对象,最后将我们尝试访问的存储结果流式传输到删除的引用或指针。

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

#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

Allows insertion and extraction of quoted strings, such as the ones found in CSV or XML.

When used in an expression 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) First, the character delim is added to the sequence

b) Then every character from s, except if the next character to output equals delim or equals escape (as determined by the stream's traits_type::eq), then first appends an extra copy of escape

c) In the end, delim is appended to seq once more

Return value

Returns an object of unspecified type such that the described behavior takes place.

而“描述的行为”就是上面的:“When used in an expression out << quoted(s, delim, escape), where out [...]”然后字符串s被输出到流中。当该字符串 s 不再存在时,您无法将其输出到流中。


实际上,cppreferece 上写的就是标准中也可以找到的,只是稍微改写了一下,不幸的是没有添加很多说明。从标准 [quoted.manip#2]:

Returns: An object of unspecified type such that if out is an instance of basic_­ostream with member type char_­type the same as charT and with member type traits_­type, which in the second and third forms is the same as traits, then the expression 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) 中发生的情况。这是您唯一可以依赖的用法。也许 note 有助于澄清:

[Note 1: Quoted manipulators provide string insertion and extraction of quoted strings (for example, XML and CSV formats). Quoted manipulators are useful in ensuring that the content of a string with embedded spaces remains unchanged if inserted and then extracted via stream I/O. — end note]

std::quoted 是一个 io 操纵器。它的 return 值不打算用于任何用途,而是要传递给流 operator<<operator>>.