Home > Enterprise >  use of deleted function ofstream
use of deleted function ofstream

Time:02-08

I have a C code with multiple files. I use g -4.8 as my compiler with Ubuntu 18.04. Upon compiling the program I face the error below. Could you please help me to fix this?

use of deleted function 'std::basic_ofstream<char>::basic_ofstream(const std::_basic_ofstream<char>)'

I did not have this error, however by adding emplace_back() to code this error showed up:

#include "FileOutputHub.h"

#include <boost/filesystem.hpp>

#include "InitialCondition.h"

using namespace std;

const char* LogFileName = "simulation_log.txt";
const char* StatsFilePrefix = "stats_";
const char* QSP_prefix = "QSP_";
const char* OdeStatsFilePrefix = "odeStats_";
const char* SnapShotDir = "/snapShots";
const char* SaveStateDir = "/savedStates";

extern InitialCondition ic;

FileOutputHub::FileOutputHub(void)
: _seed()
, _outDirBase()
, _log()
, _generalStats_core()
, _generalStats_margin()
, _lymph_blood_QSP()
, _gridSnapshotFstream()
, _makeshiftSteam()
{
}

FileOutputHub::~FileOutputHub()
{
    _log.close();
    for (auto& fs : _generalStats_core) {
        fs.close();
    }
    for (auto& fs : _generalStats_margin) {
        fs.close();
    }
}

/*!
    Process paths and setup output file streams
    \param [in] seed: seed is used as part of the ABM/ODE stats file names
    \param [in] baseDirectory: base directory for all output files

    Simulation log file is saved in the base directory. If a new simulation's output
    directory is set to be the same as an older one, new log will append to the end of
    existing log.

    ABM/ODE stats are placed inside the base directory, which has a file name including
    the seed of the simulation. If output directory exists, stats will be attached to
    existing files. This is because when loading from a saved state, if the seed is the same,
    we assume the simulation is continuation of the saved progress, and append statas to
    the end of existing stats file without writing new headers; otherwise, new header is writen,
    so output directory should be set to a new location.

    all grid snapshot output file are placed in a sub-folder "snapShots".

    all serialization (saved states) are placed in a sub-folder "savedStates".
    */
void FileOutputHub::setup(long seed, string baseDirectory){

    _seed = seed;
    _outDirBase = baseDirectory;
    
    // create directories
    boost::filesystem::path pSnap(_outDirBase   SnapShotDir);
    boost::filesystem::create_directories(pSnap);// create snapshot directory tree
    
    boost::filesystem::path pState(_outDirBase   SaveStateDir);
    boost::filesystem::create_directories(pState);// create save states directory tree

    // initialize filestreams
    string logFileName = _outDirBase   "/"   LogFileName;
    _log.open(logFileName, ios::out | ios::app);


    string statsFileName;
    for (int i = 0; i < ic.getVal(IC_NUM_ROI_core); i  ) {

        _generalStats_core.emplace_back(ofstream());
        statsFileName = _outDirBase   "/"   StatsFilePrefix   "core_" 
              to_string(i)   "_s_"   to_string(_seed)   ".csv";
        //std::cout << "file: " << i << ", " <<statsFileName << std::endl;
        _generalStats_core[i].open(statsFileName, ios::out | ios::app);
    }
    for (int i = 0; i < ic.getVal(IC_NUM_ROI_margin); i  ) {
        _generalStats_margin.emplace_back(ofstream());
        statsFileName = _outDirBase   "/"   StatsFilePrefix   "margin_" 
              to_string(i)   "_s_"   to_string(_seed)   ".csv";
        //std::cout << "file: " << i << ", " <<statsFileName << std::endl;
        _generalStats_margin[i].open(statsFileName, ios::out | ios::app);
    }

    string QSP_FileName = _outDirBase   "/"   QSP_prefix   to_string(_seed)   ".csv";
    _lymph_blood_QSP.open(QSP_FileName, ios::out | ios::app);

}


ofstream& FileOutputHub::getStatsFstream(bool core, int i){ 
    if (core)
    {
        return _generalStats_core[i]; 
    }
    else{
        return _generalStats_margin[i]; 
    }
}
/*! Create a new output file stream for grid snapshot and return the pointer
    \param [in] time: used to time stamp the file name
    \param [in] tag: goes to first part of file name 
    use case:
    std::ofstream * snap;
    snap = <FileOutputHub instance>.getNewGridToSnapshot(time, tag);
    *snap << [contents] << std::endl;
    snap->close();
*/
ofstream& FileOutputHub::getNewGridToSnapshotStream(unsigned long time, std::string tag){

    string gridSnapFileName = _outDirBase   SnapShotDir  "/"   tag   to_string(time)   ".csv";
    _gridSnapshotFstream.open(gridSnapFileName, ios::out | ios::trunc);
    return _gridSnapshotFstream;
}

/*! Create a new output file stream for serialzation and return the pointer
    \param [in] time: used to time stamp the file name
    \param [in] tag: goes to first part of file name 
    use case:
    std::ofstream * pState;
    pState = <FileOutputHub instance>.getNewSaveStateStream(time, tag);
    *pState << BOOST_SERIALIZATION_NVP(item1) << [item2] ...;
    pState->close();
    note that the NVP macro uses the variable name as xml tag; if want to use a different 
    name, use boost::serialization::make_nvp("tag", variable)
*/
ofstream& FileOutputHub::getNewSaveStateStream(unsigned long time, std::string tag){
    string saveStateFileName = _outDirBase   SaveStateDir  "/"   tag   to_string(time)   ".dat";
    _saveStateStream.open(saveStateFileName, ios::out | ios::trunc);
    return _saveStateStream;
}

/*!
    Create a new output file stream for temporary and general purposes
    \Param [in] tag: file name
    use case:
    std::ofstream * pOFS;
    pOFS = <output overseer instance>.getNewMakeshiftStream(tag);
    *pOFS << ...
    pOFS->CLOSE()
*/
ofstream& FileOutputHub::getNewMakeshiftStream(std::string tag){

    string makeShiftFileName = _outDirBase   "/"   tag;
    _makeshiftSteam.open(makeShiftFileName, ios::out | ios::trunc);
    return _makeshiftSteam;
}

image

CodePudding user response:

What you are seeing is a compiler bug.

Assuming the containers are e.g. std::vectors, .emplace_back(ofstream()) should be calling the move constructor of ofstream to construct the new vector element in-place from the temporary object created by ofstream().

Apparently your compiler version tries to use the copy constructor, but ofstream isn't copyable.

With GCC 5.1 or later it works are expected: https://godbolt.org/z/KKWKvx65a

I suggest you get a more up-to-date compiler. GCC 4.8 is very old and just barely even supports C 11.

CodePudding user response:

emplace_back() creates a new object in-place in the container, passing its constructor the input parameters passed to emplace_back().

In FileOutputHub::setup(), your 2 loops are creating a temporary ofstream object and passing it to emplace_back(), so it will try to create a new element passing that temporary ofstream to the new element's constructor.

It is clear from the error message that _generalStats_core and _generalStats_margin are holding ofstream elements, and your compiler is trying to call ofstream's copy constructor instead of its move constructor, so this will not work, as C streams are not copyable, only movable.

However, ofstream has a constructor that accepts the same input parameters as its open() method, so the loops can be re-written to not create the temporary ofstream objects at all:

for (int i = 0; i < ic.getVal(IC_NUM_ROI_core); i  ) {
    statsFileName = _outDirBase   "/"   StatsFilePrefix   "core_" 
          to_string(i)   "_s_"   to_string(_seed)   ".csv";
    //std::cout << "file: " << i << ", " << statsFileName << std::endl;
    _generalStats_core.emplace_back(statsFileName, ios::app);
}

for (int i = 0; i < ic.getVal(IC_NUM_ROI_margin); i  ) {
    statsFileName = _outDirBase   "/"   StatsFilePrefix   "margin_" 
          to_string(i)   "_s_"   to_string(_seed)   ".csv";
    //std::cout << "file: " << i << ", " << statsFileName << std::endl;
    _generalStats_margin.emplace_back(statsFileName, ios::app);
}
  •  Tags:  
  • Related