从流中提取到char数组或std :: string的最安全的方法

时间:2010-12-15 21:26:49

标签: c++ stream buffer-overflow

我担心缓冲区溢出,我需要从一个派生自std :: istream的类中获取一些字符。根据我的理解,没有办法直接从istream流式传输到std :: string,没有我自己的>>运营商。所以我正在考虑将内容流式传输到char数组,然后将其放入std :: string。这是一个简单的例子:

char CharArray[1000] = {0};
SomeIStream >> CharArray;
std::string StuffFromStream(CharArray);

然而,似乎没有办法知道CharArray不会溢出。流提取操作符会写入chararray吗?有没有办法检查预先提取多少?这有什么不对,有什么比这更好的方法吗?

Edit1:,我修复了我的内存泄漏问题。无需调用删除。我简直不敢相信。

Edit2:使用>>的建议建议直接使用字符串。我试图在代码库中的前一个问题来自,它失败了。说没有找到适合运营商的匹配。然后我尝试使用std :: fstream并再次失败。在简单的简约项目中尝试std :: fstream代码成功了。这告诉我,我的大项目还有其他问题。这个问题的初衷不再有效。

Edit3:我解决了这个问题。我试图流式传输到一个typedef String,我认为它实际上是std :: string,但它实际上是一个const std :: String。当然,没有用于写入不可写对象的流提取操作符,所以它只给了我istream头中列出的所有操作符(我需要的那个是在字符串头中)。

感谢那些指出我的错误研究并指导我正确方向的人。

5 个答案:

答案 0 :(得分:3)

如果你(正确地)继承自std :: istream,那么你不需要做任何特殊的事情就可以使用operator >> (std::istream&, std::string&)

std::string s;
SomeIStream >> s;

当我说“正确”时,我的意思是从istream中覆盖适当的虚函数。

“我知道如果在删除之前有异常,这将泄漏内存。”不,不会。您没有使用CharArray分配new;在其上调用delete将无法执行您想要的操作。

答案 1 :(得分:0)

将旧式C风格的char数组与流混合?看起来像一些非常混乱的代码。

除了评论之外,只需直接提取到字符串。您可以将其(通过c_str()方法)传递给期望const char*参数的C风格API。如果出于某种奇怪的原因你确实需要一个char数组,那么在检查边界之后,你可以安全地copystring到char数组。

顺便说一句,你已经清楚地说明了magic numbers are evil的主要方式。在您的情况下,有问题的幻数是1000。你不知道1000是否恰当 - 不是太大,也不是太小 - 没有完全猜测。在编程中,猜测经常==崩溃。或者甚至更糟,不会崩溃。

顺便说一下,你是delete上面的自动变量。你不这样做。当且仅当您使用delete时,请使用new。你没有new,所以不要delete

顺便说一下3,如果您只想将整个流提取到字符串中,您可以这样做:

string s = SomeIStream.str();

答案 2 :(得分:0)

所有流都提供.str()方法,它将提供缓冲区的副本作为std :: string(或wstring或其他typedef的任何内容)。

此外,您在堆栈上声明了一个数组,然后尝试删除它,即UB。

答案 3 :(得分:0)

如果你想把整个流读成一个字符串,这不是非常有效,但是很安全:

std::string str((std::istream_iterator<char>(some_istream)), std::istream_iterator<char>());

(注意额外的括号,以避免最烦恼的解析)

如果您想阅读“n”个字符:

some_istream.read(some_char_array, sizeof(some_char_array));

请注意,这不会使数组终止。如果你想保持数组的最后一个字符不变,请通过sizeof(char_array) - 1

答案 4 :(得分:0)

这就是我的做法(来自Bruce Eckel撰写的“Thinking in C ++”)::

ifstream in("somefile.txt",ios::in);
istreambuf_iterator istr(in),end;
string str;
insert_iterator ins(str,str.begin());

while(istr != end){
      *ins++ = *istr++;
}

在上面的代码中,整个文件被视为一个字符流,然后放入一个字符串中。这只是一个例子。