Trying to make custom "std::getline()" function (HELP!)

Hello. First off, I'd like to apologize to anyone I may have offended here.
Sorry for being mad and maybe rude. :P

Also, I was trying to make a custom version of the function,
"std::getline(std::ifstream, std::string)". This is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void read(std::ifstream& stream, std::string& buffer)
{
    static int last = 0; // This will be used to store the last read location.
    bool stop = false;
    char C;
    
    buffer = '\0';
    
    for(int i = 0; !stop; i++)
    {
        stream >> C;
        if(C != '\n')
        {
            buffer += C;
        }
        else stop = true;
        last++;
    }
}

int main () 
{
    std::ifstream stream("file.txt");
    std::string s;
    read(stream, s);
    std::cout << s;
}


The output is quite strange, it seems to request user input
and allows the user to type characters to the console.
It does nothing else.

Any idea why?

file.txt:
This should be printed to console!


Thanks in advance.

Merry Christmas! God bless you all.
Last edited on
Are you sure that there is a new line character inside your file? Your "example" doesn't seem to show one.

What happens if reading the stream fails for some reason before you encounter the new line character?

Did you try printing C inside the loop, or run the program in your debugger to try to "see" what is actually happening?

Also your function should be using an istream& not an ifstream&, then you can use any input stream not just an ifstream. You probably should be returning the stream if you're really trying to mimic std::getline().

read should take an istream not an ifstream since it's not using any of the extra ifstream methods (like open or close).

You should use the get method instead of operator>> since you obviously don't want to skip whitespace, otherwise you will never see a newline.

Assigning a null char to buffer is just weird. '\0' is not generally special to std::string. You're thinking of C-style strings. To ensure the string is empty, use its clear method.

Returning the stream is handy for checking for eof.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <string>

std::istream& read(std::istream& in, std::string& line)
{
    line.clear();
    for (char c; in.get(c) && c != '\n'; ) line += c;
    return in;
}

int main()
{
    std::string s;
    read(std::cin, s);
    std::cout << s << '\n';
}

Oh, ok. Thanks, I'll try what you said.

EDIT:
I added std::cout << C; right before buffer += C;
It absolutely fills the console with '!' characters... Idk why...

EDIZT (2): Sorry, dutch's post just loaded in. It works! Thanks! :D
Last edited on
Actually the function could really be better, in one way:
It only reads a line if it ends with '\n' which is ok, but
you have to input a newline after the last line all the time...
This can get annoying. Any suggestions as to how I can
improve this? Other than that the function works great.

Thanks.
Last edited on
I'm not entirely sure what you're getting at.
I wrote it to stop whether it hits a newline or the end of the file.
That's about all you can do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <fstream>
#include <string>

std::istream& read(std::istream& in, std::string& line)
{
    line.clear();
    for (char c; in.get(c) && c != '\n'; ) line += c;
    return in;
}

int main()
{
    std::ifstream in("file.txt");
    std::string s;

    // This should read and print the whole file
    while (read(in, s))
        std::cout << s << '\n';
}

Ok, the file looks like this:
1. Hello, world!
2. Another line printed. (1)
3. Another line printed. (2)


3 lines. No new line character after third line.
To make it print
Hello, world!
Another line printed. (1)
Another line printed. (2)


I would have to edit the file to look like this:
1. Hello, world!
2. Another line printed. (1)
3. Another line printed. (2)
4.


In other words, a newline character has to be after the last line.
Otherwise, it would print only the first 2 lines. I don't really know
why. The code looks like it should work perfectly.
Last edited on
You're right. The problem is that if it hits the eof after it's read some chars into line it still returns "in" in the eof state which causes our loop to stop. So if the line is not empty it should return "in" in the clear state, even if it's hit eof. Let it detect eof the next time read is called.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <fstream>
#include <string>

std::istream& read(std::istream& in, std::string& line)
{
    line.clear();
    for (char c; in.get(c) && c != '\n'; ) line += c;
    if (in.eof() && line.size()) in.clear();
    return in;
}

int main()
{
    std::ifstream in("file.txt");
    std::string s;
    while (read(in, s))
        std::cout << s << '\n';
}

Note that "clear" for a string means to empty the string, but "clear" for a stream means to clear the state flags.
Last edited on
Thanks, that does it! :D
Thanks for the tips.
> Also, I was trying to make a custom version of the function, "std::getline(std::ifstream, std::string)"

This is slightly tricky because of the requirement:
Behaves as UnformattedInputFunction, except that input.gcount() is not affected.
https://en.cppreference.com/w/cpp/string/basic_string/getline
(I guess the standard specifies that gcount() is not affected to make the operation more efficient)

A typical conforming library implementation would pick up the characters directly from the associated stream buffer.
For example, libc++ reads the next character with: typename _Traits::int_type __i = __is.rdbuf()->sbumpc();
https://github.com/llvm-mirror/libcxx/blob/018a3d51a47f7275c59e802709104498b729522b/include/istream#L1554
You should use the get method instead of operator>> since you obviously don't want to skip whitespace, otherwise you will never see a newline.


You can use the input manipulator noskipws to prevent skipping of white space when extracting from a stream.

 
stream >> noskipws >> C;


See https://en.cppreference.com/w/cpp/io/manip
Topic archived. No new replies allowed.