CodingKnight's blog

By CodingKnight, 23 months ago, In English

Hello Codeforces,

It is sometimes required in competetive programming problems to use fast data input/output and/or read and write problem data from and to data files. It is well known that the C++ standard libray functions std::ios_base::sync_with_stdio(), std::basic_io::tie(), and std::freopen() can be used to peform the sought input/output initializtion. The following is a C++ io_init class that simplifies this initialization by encapsulating it inside public class constructors.

#include <bits/stdc++.h>
using namespace std;

class io_init {
    struct fast { fast() { ios_base::sync_with_stdio(false), cin.tie(nullptr); } } io;
    void reopen(const string &file_name, const char *mode, FILE *stream) {
        if (freopen(file_name.c_str(),mode,stream) == nullptr) 
            throw runtime_error("freopen() failed: cannot open file "+file_name); }
public:
    io_init() {}
    io_init(const string &data) { reopen(data+".in","r",stdin), reopen(data+".out","w",stdout); } };
		    
int main() { 
     io_init(); // io_init("data"); 
    // solution
}

The first class constructor without parameter initializes fast input/output by creating the io instance of the private data structure fast. The second class constructor with string data paremeter performs the same operation, and then initializes the data input/output to read data from input file data+".in" and write results to output file data+".out". The private class member function reopen() throws a run-time error exception if the freopen() function call returns nullptr.

Your constructive comments and feedback are welcome and appreciated.

UPDATE

The following alternative to use a fuction call instead of using public class constructors is favored by Actium.

#include <bits/stdc++.h>
using namespace std;

void io_init(const string &data = "") { 
    const auto reopen = [data](const string &ext, const char *mode, FILE *stream) {
        const string file_name = data+"."+ext;
        if (freopen(file_name.c_str(),mode,stream) == nullptr)
            throw runtime_error("freopen() failed: cannot open file "+file_name); };
    if (ios_base::sync_with_stdio(false), cin.tie(nullptr), not data.empty())
        reopen("in","r",stdin), reopen("out","w",stdout); }
		    
int main() {
    io_init(); // io_init("data");
}

A third alterntative (favored by spookywooky) that does not require a function call to be included in the main() function is to declare io_init as a named lambda expression as follows.

#include <bits/stdc++.h>
using namespace std;
     
const auto io_init = [](const string &data = "") {
    const auto reopen = [data](const string &ext, const char *mode, FILE *stream) {
        const string file_name = data+"."+ext;
        if (freopen(file_name.c_str(),mode,stream) == nullptr)
            throw runtime_error("freopen() failed: cannot open file "+file_name); };
    if (ios_base::sync_with_stdio(false), cin.tie(nullptr), not data.empty())
        reopen("in","r",stdin), reopen("out","w",stdout); 
        return 0; } (); // ("data");
    
int main() {
    // solution
}

A fourth alterntative and perhaps the simplest way to initialize data input/output files for read/write is to create std::ifsteam and std::ofstream objects. Names other than cin and cout should be used for the created object if using namespace std; is part of the program so as to avoid name redeclaration errors.

#include <bits/stdc++.h>
using namespace std;
     
ifstream  i_data("data.in");
ofstream  o_data("data.out");

#define cin  i_data
#define cout o_data

int main() {
    
   int a, b; 

   cin >> a >> b;        // read (a) and (b) from file data.in

   cout << a+b << endl;  // write (a+b) to file data.out
}
 
 
 
 
  • Vote: I like it
  • -23
  • Vote: I do not like it

»
23 months ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

I think it is enough to have a single function and call it from main(), that is class io_init + nested class fast are just overcomplication in my opinion.

  • »
    »
    23 months ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    Thanks for your feedback. I appreciate your opinion. Note that the class constructor can be called from the main() function just like any other function if it not necessary to store the object reference explicitly using a variable name. Check the updated main() function for an illustration.

    • »
      »
      »
      23 months ago, # ^ |
        Vote: I like it 0 Vote: I do not like it

      Even object construction looks as a function call ;) Just make it a function that takes single argument (filename) with default value and does all the initialization work.

      • »
        »
        »
        »
        23 months ago, # ^ |
        Rev. 3   Vote: I like it 0 Vote: I do not like it

        Check the update section. It does seem that the function call is simpler and more favored. It is even less by one line than the class implementation :-) Thanks again for your constructive feedback.

»
23 months ago, # |
  Vote: I like it 0 Vote: I do not like it

" throw runtime_error("freopen() failed: cannot open file "+file_name); }; " for this line, even for a hello world it is signalling : "[Error] 'runtime_error' was not declared in this scope"...

  • »
    »
    23 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    You have to add #include <stdexcept>

  • »
    »
    23 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    std::runtime_error is a standard C++ class. Just use #include <bits/stdc++.h> in case that #include <iostream> does not automatically include the C++ error handling library.

»
23 months ago, # |
  Vote: I like it 0 Vote: I do not like it

I prefer a static initializer, it is called before main(), example

const bool ready = [](){
    ios_base::sync_with_stdio(false); cin.tie(0);
    cout << fixed << setprecision(12);
    return true;
}();

signed main() {
  // no init call nessecary
}
  • »
    »
    23 months ago, # ^ |
      Vote: I like it +5 Vote: I do not like it

    Thanks for your feedback. I have just added this third alternative to the update section before reading your comment.