Search code examples
c++visual-c++boostboost-filesystem

Why does vector always stay empty?


So, the program takes a path to folder as command line option, then reads all the files in folder and if the file contents is correct (it should be an integer), it outputs the filename and an integer (example: test.txt : 192), check() function determines if the file data is correct.

After all good files are printed, I want to print all bad files too. so I try collect their names in vector<string>, but unfortunately it always remains empty. All the logic is in print() function because the program should process files using multiple threads. When I don't use threads everything works just fine.

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<iomanip>
#include<regex>
#include<boost/algorithm/algorithm.hpp>
#include<boost/range/algorithm.hpp>
#include<boost/filesystem.hpp>
#include<locale>
#include<thread>

using std::cout;
using std::endl;
using namespace boost::filesystem;
using vec = std::vector<std::string>;
static int summ = 0;
static vec vc;

inline auto check(const std::string &s)
{
    std::regex reg1("[[:blank:]]*[-[:digit:]]*[[:blank:]]*", std::regex_constants::ECMAScript);
    return regex_match(s, reg1);
}

void print(boost::filesystem::directory_entry &dir,std::vector<std::string> &v)
{
std::ifstream is;
is.open(dir.path().string());
std::stringstream buf;
buf << is.rdbuf();
auto temp = buf.str();
if(!check(temp))
{
    vt.push_back(dir.path().filename().string());
    is.clear();
    is.close();
    return;
}
cout.setf(std::ios::left, std::ios::adjustfield);
cout << std::setw(20) << dir.path().filename().string() << ": " << std::stoi(temp) << endl;
is.clear();
is.close();
}


int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
int sum{};
std::vector<std::string> vt;
std::ifstream file;

if (argc < 2)
{
    cout << "usage: prog path" << endl;
    return 1;
}

boost::filesystem::path p(argv[1]);

if (!boost::filesystem::is_directory(p))
{
    cout << "not a directory!";
    return 1;
}
for (auto &el : boost::filesystem::directory_iterator(p))
{
    if (!boost::filesystem::is_directory(el))
    {
        std::thread tr(print, el,vc);
        tr.join();
    }

}
//cout << "Sum: " << sum << endl;
cout << "Files with wrong input data: \n";
boost::copy(vt, std::ostream_iterator<std::string>(cout, "\n"));   //empty here
}

Solution

  • Problem:

    vt is empty because you're never adding anything to it. You're passing vc into print. Even if you were passing vt into print, it wouldn't compile as you're calling push_back on non-existent variable vt inside print. You probably mean v, the name of the parameter.

    Solution:

    1. Get rid of either static vec vc; or std::vector<std::string> vt; in main
    2. Call v.push_back instead of vt.push_back in print

    Also:

    1. std::vector.push_back is not thread safe, so you should lock if you're accessing it on multiple threads concurrently... which you're not because:
    2. You're not actually parallelising anything, as you're immediately joining after launching each thread.
    3. Disk IO is going to be the bottleneck, so even if you were parallelising the check, it will probably not be any faster.