That streams are always slower than the C-API functions is a pretty common misconception because by default, they synchronize with the C-layer. So yeah, that's a feature, not a bug.
Without sacrificing type safety (and readability, depending on your taste), you possibly gain performance with streams by using:
std::ios_base::sync_with_stdio (false);
A little indicator:
#include <cstdio>
#include <iostream>
template <typename Test>
void test (Test t)
{
const clock_t begin = clock();
t();
const clock_t end = clock();
std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}
void std_io() {
std::string line;
unsigned dependency_var = 0;
while (!feof (stdin)) {
int c;
line.clear();
while (EOF != (c = fgetc(stdin)) && c!='\n')
line.push_back (c);
dependency_var += line.size();
}
std::cout << dependency_var << '\n';
}
void synced() {
std::ios_base::sync_with_stdio (true);
std::string line;
unsigned dependency_var = 0;
while (getline (std::cin, line)) {
dependency_var += line.size();
}
std::cout << dependency_var << '\n';
}
void unsynced() {
std::ios_base::sync_with_stdio (false);
std::string line;
unsigned dependency_var = 0;
while (getline (std::cin, line)) {
dependency_var += line.size();
}
std::cout << dependency_var << '\n';
}
void usage() { std::cout << "one of (synced|unsynced|stdio), pls\n"; }
int main (int argc, char *argv[]) {
if (argc < 2) { usage(); return 1; }
if (std::string(argv[1]) == "synced") test (synced);
else if (std::string(argv[1]) == "unsynced") test (unsynced);
else if (std::string(argv[1]) == "stdio") test (std_io);
else { usage(); return 1; }
return 0;
}
With g++ -O3, and a big text file:
cat testfile | ./a.out stdio
...
0.34 sec
cat testfile | ./a.out synced
...
1.31 sec
cat testfile | ./a.out unsynced
...
0.08 sec
How this applies to your case depends. Modify this toy-benchmark, add more tests, and compare e.g. something like std::cin >> a >> b >> c
with scanf ("%d %d %d", &a, &b, &c);
. I guarantee, with optimizations (i.e. without being in debug mode), performance differences will be subtle.
If that does not saturate your needs, you might try other approaches, e.g. reading the whole file first (may or may not bring more performance) or memory maps (which is a non-portable solution, but the big desktops have them).
Update
Formatted input: scanf vs. streams
#include <cstdio>
#include <iostream>
template <typename Test>
void test (Test t)
{
const clock_t begin = clock();
t();
const clock_t end = clock();
std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}
void scanf_() {
char x,y,c;
unsigned dependency_var = 0;
while (!feof (stdin)) {
scanf ("%c%c%c", &x, &y, &c);
dependency_var += x + y + c;
}
std::cout << dependency_var << '\n';
}
void unsynced() {
std::ios_base::sync_with_stdio (false);
char x,y,c;
unsigned dependency_var = 0;
while (std::cin) {
std::cin >> x >> y >> c;
dependency_var += x + y + c;
}
std::cout << dependency_var << '\n';
}
void usage() { std::cout << "one of (scanf|unsynced), pls\n"; }
int main (int argc, char *argv[]) {
if (argc < 2) { usage(); return 1; }
if (std::string(argv[1]) == "scanf") test (scanf_);
else if (std::string(argv[1]) == "unsynced") test (unsynced);
else { usage(); return 1; }
return 0;
}
Results:
scanf: 0.63 sec
unsynced stream: 0.41