编写自定义输入操纵器

Writing a custom input manipulator

提问人:nameses 提问时间:6/8/2022 更新时间:6/8/2022 访问量:352

问:

我需要制作一个自定义 istream 操纵器,该操作器从输入中读取 5 个字符,然后从输入中跳过 5 个字符,并执行到字符串末尾。例:

string line;
cin >> skipchar >> line;

这是我做的,但由于某种原因它不起作用。另外,如果我不使用,那就更好了<sstream>

struct membuf : streambuf
{
    membuf(char* begin, char* end) {
        this->setg(begin, begin, end);
    }
};
istream& skipchar(istream& stream)
{
    string temp;
    getline(stream, temp);
    char *str = new char[temp.size() + 1];
    strcpy(str, temp.c_str());//get string and convert to char*

    char* res = new char[strlen(str)];
    for (int i=0,j=0;i<strlen(str);i++)
        if ((i / 5) % 2 == 0) //get first 5, then 5 skip, etc
            res[j++] = str[i];

    membuf b(res, res + strlen(res)); //copy str to buffer
    stream.rdbuf(&b);
    return stream;
}
int main()
{
    string str;
    cout << "enter smth:\n";
    cin >> skipchar >> str;
    cout << "entered string: " << str;
    return 0;
}  
C++ IStream Streambuf 操纵器

评论


答:

1赞 Remy Lebeau 6/8/2022 #1

您没有显示您的意见,但我认为在这种情况下使用不适合。 意思是读一个字,而不是一整行。getline()operator>>

无论如何,您都会泄漏您分配的两个数组。使用完它们后,您需要使用它们。对于数组(仅供参考,您实际上并不需要,因为您可以将字符串中的字符直接复制到其中),您可以在退出之前使用它。但是对于 ,当 本身不再被使用时,它必须保留该指针和它。char[]delete[]strtempresdelete[]resmembufdelete[]membuf

但是,更重要的是,你使用您正在将其创建为 的局部变量,因此它将在退出时被销毁,留下指向无效对象的悬空指针。分配给 的指针必须在分配给 的整个持续时间内保持有效,这意味着使用 创建对象,然后调用方必须记住稍后手动操作它(这有点违背了使用 的目的)。但是,流操纵器实际上不应该首先更改所指向的内容,因为在后续读取操作完成后,没有一种好的方法可以恢复以前的操作(除非您定义另一个操纵器来处理它,即)。membufskipchar()skipchar()streamstreambuf*streamistreammembufnewdeleteoperator>>rdbufstreamstreambufcin >> skipchar >> str >> stopskipchar;

在这种情况下,我建议采取不同的方法。不要创建流操纵器,将 new 分配给 ,从而影响所有后续调用。取而代之的是,创建一个引用输出变量的操纵器,然后从 和 仅输出所需的内容(类似于 std::quoted 和 std:get_time 等标准操纵器的工作方式),例如:streambufstreamoperator>>stream

struct skipchars
{
    string &str;
};

istream& operator>>(istream& stream, skipchars output)
{
    string temp;
    if (stream >> temp) {
        for (size_t i = 0; i < temp.size(); i += 10) {
            output.str += temp.substr(i, 5);
        }
    }
    return stream;
}

int main()
{
    string str;
    cout << "enter smth:\n";
    cin >> skipchars{str};
    cout << "entered string: " << str;
    return 0;
}

在线演示

或者:

struct skipcharsHelper
{
    string &str;
};

istream& operator>>(istream& stream, skipcharsHelper output)
{
    string temp;
    if (stream >> temp) {
        for (size_t i = 0; i < temp.size(); i += 10) {
            output.str += temp.substr(i, 5);
        }
    }
    return stream;
}

skipcharsHelper skipchars(string &str)
{
    return skipcharsHelper{str};
}

int main()
{
    string str;
    cout << "enter smth:\n";
    cin >> skipchars(str);
    cout << "entered string: " << str;
    return 0;
}

在线演示

评论

0赞 nameses 6/8/2022
谢谢!但是我需要在代码中使用操纵器,输入应该是这样的:cin >> skipchar >>行;这就是为什么我开始使用流和membuf的原因。
0赞 Remy Lebeau 6/8/2022
"输入应如下所示:cin >> skipchar >>行;”- 对不起,但是没有安全的方法可以按照您想要的方式实现该语法(无论如何,我知道)。我建议的方法有什么问题?这是标准库实现此类操纵器的方式,那么为什么不能遵循相同的模式呢?
0赞 nameses 6/8/2022
你的建议是完美的,但这就是任务的给出方式。好吧,如果你说这是解决这个问题的唯一方法,我会听从你的建议。再次感谢)
0赞 Remy Lebeau 6/8/2022
"这就是任务的下达方式“——那么你的任务就被误导了。这种方式不是流操纵器的使用方式。