Lines 7-8 can be combined in to one line. std::fstream file("C:/Users/Myname/Desktop/test.txt");
Line 10: Why not use a for loop ?
Line 11: Why continue ?
Line 19: If the exercise says you should read integer numbers, why reading a string?
#include <iostream>
#include <fstream>
#include <string>
int main() {
constint numbers[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
const std::string path_to_file = "C:/Users/Myname/Desktop/test.txt" ;
// Write integer numbers into a text file
if( std::ofstream file{path_to_file} ) // if the file is opened for output
{
for( int n : numbers ) file << n << ' ' ; // *** add a white space as separator
/* std::cout */ file << '\n' ; // good idea to end the text file with a new line
} // file is automagically closed
else
{
std::cerr << "failed to open file for output\n" ;
return 1 ;
}
// and then read from them
if( std::ifstream file{path_to_file} ) // if the file is opened for input
{
int n ;
while( file >> n ) std::cout << n << ' ' ;
std::cout << '\n' ;
} // file is automagically closed
else
{
std::cerr << "failed to open file for input\n" ;
return 2 ;
}
}
1- You're using an array in modern C++ code.
2- You've eliminated .open , .is_open() APIs.
3- The file is closed right after exiting the if block, automagically.
To see using a std::vector change line 7 to const std::vector<int> numbers { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
AND make sure you add #include <vector> !
Compile and test, it runs the same.
If'n you compiled as C++17 (or later) creating a std::vector could be done as const std::vector numbers { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; The type (int) is deduced by the initializer list.
As I see it, there is nothing wrong in using a classical array in modern C++ code, provided that it has a fixed constant size, and it is used only within the local scope where it is defined.
> You've eliminated .open , .is_open() APIs.
They are implicit within the condition of the if statement: the constructor of the object calls open() and operator bool verifies that the stream is ready for i/o.
> The file is closed right after exiting the if block, automagically.
Yes, the destructor of the object closes the file.
> shouldn't line 14 be writing the new line to the file instead of std::cout?
It's ok to use older constructs, and the size of the array is known within the scope of its declaration. If it's passed around, only a pointer is passed, so be careful.
This is also more efficient than using a std::vector, as that requires an allocation and release from the heap. If you don't care about efficiency, why put yourself thru the grief of learning C++? You may as well use Python or Ruby.
2- You've eliminated .open , .is_open() APIs.
fstreams aren't just files, they're streams. Streams have a state (good/bad/eof/fail), you only need to check if it's good if all you want to know is that all's ok. That's why that construct is in an if statement.
3- The file is closed right after exiting the if block, automagically.
Yes, the file is closed. No, it's not magic. It's a feature of objects having constructors and destructors. Constructors initialize the object before use (this is why you shouldn't call open()), and destructors release resources when you're done with the object (this is why you shouldn't call close()). Think stream, not file.
#include <iostream>
int main() {
if (int a {6})
std::cout << a << " != 0";
}
where the if condition test is the result of defining a and assigning 6 to it (ie. 6) and where the scope of a is within the if statement. This is similar to the use of std::ofstream within an if statement condition to open a file.
> if (int a {6})
> if condition test is the result of defining a and assigning 6 to it
There is no assignment: this is initialisation. The condition is evaluated in a bool context.
Try this: if ( constint a = 6 ) std::cout << a << " != 0\n";
as expected. Sorry for my in-exact wording. I tend to interchange assignment/initialisation when defining a variable. In my over 25 years of using C++ I've never read a c++ standard. Oh dear... :) :)
There used to be a difference between myclass mc = 6; and myclass mc (6); - the first called assignment after a default constructor and the second called a constructor. Now they both call the constructor.
When the life-time of the object ends.
For an object in the condition of an if statement, life-time begins at the point of its declaration
and ends at the end of the if statement.
1 2 3 4
if( std::ofstream file{path_to_file} ) // if the file is opened for output
{
// ...
} // destructor is called here; the if statement ends here and the end of life-time of file is reached
So it does not necessarily hinges upon the curly brackets of the if-statement and even if we write that this way, it works:
1 2 3 4 5
if( std::ofstream file{path_to_file} ) // if the file is opened for output
for( int n : numbers )
file << n << ' ' ; // *** add a white space as separator
// Here when the for-loop ends, the if-statements, too, ends
// so the destructor for the file object is called
> What makes you define the class inside main()?
> Classes/structs are normally defined outside the main function
The class is required only within the function main(); so make it local to the function main().
Many classes (types) are designed to be used in more than one function; ergo, they would be declared at namespace scope.
A class declaration can appear inside the body of a function, in which case it defines a local class. The name of such a class only exists within the function scope, and is not accessible outside. https://en.cppreference.com/w/cpp/language/class#Local_classes
This is somewhat similar to variable declarations; a variable that is required only within a block would be declared at block scope.