简体   繁体   English

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

[英]Safest way to extract from stream to char array or std::string

I am concerned about buffer overflows, and I need to get some characters out of a class that derives from std::istream. 我担心缓冲区溢出,我需要从std :: istream派生的类中获取一些字符。 From what I understand there is no way to stream to an std::string directly from an istream, without my own >> operator. 据我了解,没有我自己的>>运算符,就无法直接从istream流式传输到std :: string的方法。 So I was considering streaming the contents to a char array, then putting that into a std::string. 因此,我正在考虑将内容流式传输到char数组,然后将其放入std :: string中。 Here is a simple example: 这是一个简单的示例:

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

However, there seems to be no way to know that CharArray will not be overflowed. 但是,似乎没有办法知道CharArray不会溢出。 Is there some maximum the stream extraction operator will write to chararray? 流提取运算符将写入chararray的最大值吗? Is there some way to check how much will be extracted preemptively? 有什么方法可以检查要抢先提取的量吗? Is this just all wrong, Is there some way that is much better than this? 这是否全是错误的,有没有比这更好的方法了?

Edit1:, I fixed my not a memory leak. Edit1 :,我修复了我的内存不泄漏。 No need to call delete. 无需致电删除。 I can't believe I did that. 我不敢相信我做到了。

Edit2: The suggestion to use the >> directly to string was suggested. Edit2:建议直接使用>>来字符串。 I attempted that previous in the code base this problem came from and it failed. 我试图在代码库中以前解决这个问题,但失败了。 Saying that no suitable match for the operator could be found. 说找不到适合操作员的匹配项。 I then tried with an std::fstream and it failed again. 然后,我尝试使用std :: fstream,但再次失败。 Trying the std::fstream code in simple minimalistic project succeeded. 在简单的简约项目中尝试std :: fstream代码成功。 This tells me that something else is wrong with my larger project. 这说明我的较大项目有其他问题。 The original intent of this question is no longer valid. 该问题的原始意图不再有效。

Edit3: I solved this. Edit3:我解决了这个问题。 I was attempted to stream to a typedef String, which I thought was actually and std::string, but it was really a const std::String. 我试图流式传输到typedef字符串,我认为它实际上是std :: string,但这实际上是一个const std :: String。 Naturally there isn't a stream extraction operator for writing to an unwritable object, so it just gave me all the operators listed in the istream header (the one I needed was in the string header). 自然地,没有写一个不可写对象的流提取运算符,所以它只是给了我istream标头中列出的所有运算符(我需要的是字符串标头中的运算符)。

Thanks to the people who pointed out my faulty research and pointe me in the right direction. 感谢那些指出我的错误研究并指出正确方向的人们。

If you've (properly) inherited from std::istream, then you don't need to do anything special and can just use operator >> (std::istream&, std::string&) . 如果您(正确地)继承自std :: istream,那么您不需要做任何特殊的事情,只需使用operator >> (std::istream&, std::string&)

std::string s;
SomeIStream >> s;

When I say "properly," I mean overridden the appropriate virtual functions from istream. 当我说“正确”时,我的意思是从istream覆盖适当的虚函数。

"I know that if there is an exception before the delete this will leak memory." “我知道,如果删除前有异常,则会泄漏内存。” No it won't. 不,不会。 You didn't allocate CharArray with new ; 您没有为CharArray分配new calling delete on it will not do what you want. 对它调用delete不会做您想要的。

Mixing old-school C-style char arrays with streams? 将流派的老式C样式char数组与流混合? Seems like some very confused code. 似乎有些非常混乱的代码。

Commentary aside, just extract directly to a string. 除了注释,只需将其直接提取为字符串即可。 You can pass that (via the c_str() method) to C-style APIs that expect const char* parameters. 您可以(通过c_str()方法)将其传递给需要const char*参数的C风格的API。 And if for some bizarre reason you really do nead a char array, you can copy from the string to the char array safely, after checking bounds. 而且,如果出于某种奇怪的原因,您确实需要一个char数组,则可以在检查界限之后copystring安全地copy到char数组。

By the way, you've pretty clearly illustrated the main way in which magic numbers are evil . 顺便说一下,您已经很清楚地说明了魔术数字是邪恶的主要方法。 In your case, the magic number in question is 1000 . 在您的情况下,所讨论的幻数是1000 You have no idea that 1000 is appropriate -- not too big, not too small -- without totally guessing. 您不知道1000是合适的-不会太大,也不会太小-完全没有猜测。 In programming, guessing often == crashing. 在编程中,猜测经常==崩溃。 Or even worse, not crashing. 甚至更糟,不会崩溃。

By the way 2, you are delete ing an automatic variable above. 顺便说一句2,您正在delete上面的自动变量。 You don't do this. 你不这样做。 Use delete if and only if you use new . 仅当您使用new时,才使用delete You didn't new , so don't delete . 您不是new ,所以不要delete

By the way 3, if you just want to extract the whole stream in to a string, you can just do this: 顺便说一句3,如果您只想将整个流提取到一个字符串中,则可以执行以下操作:

string s = SomeIStream.str();

All streams offer the .str() method, which will provide a copy of their buffer as a std::string (or wstring or whatever for other typedefs). 所有流都提供.str()方法,该方法将以std :: string(或wstring或其他typedef的形式)的形式提供其缓冲区的副本。

Also, you declared an array on the stack and then tried to delete it, which is UB. 另外,您在堆栈上声明了一个数组,然后尝试删除它,即UB。

If you want to read the whole stream into a string, this is not terribly efficient, but is safe: 如果您想将整个流读取为字符串,则效率不高,但是很安全:

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

(note the extra parenthesis, to avoid the most-vexing-parse) (请注意额外的括号,以避免最烦人的解析)

If you want to read up to "n" characters: 如果要最多读取“ n”个字符:

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

note that this won't null-terminate the array. 请注意,这不会对数组进行null终止。 Pass sizeof(char_array) - 1 instead if you want to leave the array's last char untouched. 传递sizeof(char_array) - 1如果要保留数组的最后一个字符不变,则传递sizeof(char_array) - 1

This is what my approach usually is (from "Thinking in C++" by Bruce Eckel):: 这就是我通常的做法(摘自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++;
}

In the above code the whole file is taken as a character stream and then put into a string. 在上面的代码中,整个文件被当作一个字符流,然后放入一个字符串中。 This is shown just as an example. 这仅作为示例显示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM