Home > Blockchain >  std::map with Filename as key and Filedescriptor as Value
std::map with Filename as key and Filedescriptor as Value

Time:11-19

I am iterating through a vector, and each entry in the vector has to be written to a file depending on the entry.

Let's say Vector {File A, File B, File C, File A....}

So, multiple file descriptors are open and I am storing them in a std::map:

Key = Filename and Value = FileDescriptor. See code below.

When a Filename is not found in the map, I insert into the map a pair of data (filename, filedescriptor). The compiler is throwing an error. See error details below after the code.

std::map <std::string, std::ofstream> filemap; // maintains filename for each item in the list.

std::vector <std::string> items;

for (i=0 ; i < items.size() ; i  ) {

  if (keyfilemap.find(items[i]) == keyfilemap.end()) {
      std::ofstream ofs (items(i), std::ofstream::out);
      ofs << key.first << "-" << key.second << std::endl;
      // **Compiler throws an error here.**
      keyfilemap.insert(std::make_pair(filename, ofs));
        
  }
  else 
     keyfilemap[filename] << key.first << "-" << key.second << std::endl;
}

Compiler Error.

/usr/include/c  /7/bits/stl_pair.h:529:14: error: no matching function for call to 'std::pair<std::__cxx11::basic_string<char>, std::basic_ofstream<char> >::pair(std::__cxx11::basic_string<char>&, std::basic_ofstream<char>&)'
       return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y));

CodePudding user response:

C stream classes are not copyable, but you are trying to make copies when constructing your std::pair for insert(). That is why the code is failing to compile.

You will have to either construct the std::ofstream objects inside the map directly, or at least transfer ownership into the map using move semantics, eg:

std::map<std::string, std::ofstream> filemap;
std::vector<std::string> items;
...
for (const auto &filename : items) {
  auto iter = filemap.find(filename);
    if (iter == filemap.end()) {
        iter = filemap.emplace(filename, filename).first;
        // or:
        // iter = filemap.emplace(make_pair(filename, ofstream(filename))).first;
        // or:
        // std::ofstream ofs(filename);
        // iter = filemap.insert(std::make_pair(filename, std::move(ofs))).first; 
    }
    iter->second << key.first << "-" << key.second << std::endl;
}

Alternatively, just let the std::map default-construct the std::ofstream objects for you, and then you can open() them when needed, eg:

std::map<std::string, std::ofstream> filemap;
std::vector<std::string> items;
...
for (const auto &filename : items) {
    auto &ofs = filemap[filename];
    if (!ofs.is_open()) {
        ofs.open(filename);
    }
    ofs << key.first << "-" << key.second << std::endl;
}

CodePudding user response:

Is this perhaps what you want to achieve?:

#include <fstream>
#include <string>
#include <unordered_map>

int main()
{
    std::unordered_map<std::string, std::ios_base::openmode> fname_to_fstream_pairs = {{"vacation.png", std::ofstream::out}, {"diary.txt", std::ofstream::in}};

    auto const& fname_to_fstream_pair = fname_to_fstream_pairs.find("vacation.png");

    if (fname_to_fstream_pair != std::end(fname_to_fstream_pairs))
    {
        std::ofstream ofs(fname_to_fstream_pair->first, fname_to_fstream_pair->second);
        ofs << "The vacation was great!";
    }

    return 0;
}

std::end denotes an element that is past the end of a container. So, usually it == std::end(v) is not what you want.

PS: Oh, and you shouldn't write out to a photo that way. That was just a silly example.

  • Related