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;
}
CodePudding user response:
What you are seeing is a compiler bug.
Assuming the containers are e.g. std::vector
s, .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);
}