I am trying to create a vector of a class which contains ofstream object as one of its member. The problem I am facing is that when I add single element to the vector, it work fine. As soon as I add another element to the vector, it changes the address of the ofstream object of the previously added element. As the address changes, I can not write to the file pointed to by that ofstream object. The example program in which I am just printing the elements value after adding two elements to the vector is given below:

#include <fstream>
using namespace std;

class routecaseBasedCDRFile
        routecaseBasedCDRFile(const routecaseBasedCDRFile& obj);
        routecaseBasedCDRFile() ;
        ~routecaseBasedCDRFile() ;
        routecaseBasedCDRFile& operator=(const routecaseBasedCDRFile& rhs);

        string routecaseName;
        string myRouteCaseBasedFilename;
        bool myRouteCaseBasedFileOpen;

        unsigned long  myRouteCaseBasedCDRFileSequenceNumber;
        long myCurrentNumOfRecordsWrittenInRouteCaseBasedFile;

        ofstream myRouteCaseBasedOutCDRfile; // This is the output file

        bool isRouteCaseBasedFileOpen() {}
        void closeRouteCaseBasedFile() {}
        void checkRouteCaseBasedFileTimeLimit() {}
        int openNewRouteCaseBasedFile() {}
        //int openNewRouteCaseBasedFile(CallDetailRecord &cdr);

routecaseBasedCDRFile::routecaseBasedCDRFile(const routecaseBasedCDRFile &obj)
  cout<<"routecaseBasedCDRFile::routecaseBasedCDRFile(const routecaseBasedCDRFile &obj)"<<endl;
 *this = obj;



routecaseBasedCDRFile& routecaseBasedCDRFile::operator=(const routecaseBasedCDRFile& rhs)
 cout<<"routecaseBasedCDRFile::operator=(const routecaseBasedCDRFile& rhs)"<<endl;
 routecaseName = rhs.routecaseName;
 myRouteCaseBasedFilename = rhs.myRouteCaseBasedFilename;
 myRouteCaseBasedFileOpen = rhs.myRouteCaseBasedFileOpen;
 myrouteCaseBasedcdrSeqNumber = rhs.myrouteCaseBasedcdrSeqNumber;
 myRouteCaseBasedCDRFileSequenceNumber = rhs.myRouteCaseBasedCDRFileSequenceNumber;
 myCurrentNumOfRecordsWrittenInRouteCaseBasedFile = rhs.myCurrentNumOfRecordsWrittenInRouteCaseBasedFile;


int main()
  vector<routecaseBasedCDRFile> routecaseFileVector;
  routecaseBasedCDRFile routecaseCDRFile1,routecaseCDRFile2;

  routecaseCDRFile1.routecaseName = "no_routecase";
  routecaseCDRFile1.myrouteCaseBasedcdrSeqNumber = 0;
  routecaseCDRFile1.myRouteCaseBasedFileOpen = false;
  routecaseCDRFile1.myCurrentNumOfRecordsWrittenInRouteCaseBasedFile = 0;
  routecaseCDRFile1.myRouteCaseBasedCDRFileSequenceNumber = 0;

  for(vector<routecaseBasedCDRFile>::iterator i=routecaseFileVector.begin();i != routecaseFileVector.end();i++)
        if((*i).routecaseName == "no_routecase")
                (*i).myRouteCaseBasedFilename = "/tmp/file1.txt";

 for( vector<routecaseBasedCDRFile>::iterator j=routecaseFileVector.begin();j != routecaseFileVector.end();j++)
       cout <<"PRINT 1::(*j).myRouteCaseBasedOutCDRfile is "<<(*j).myRouteCaseBasedOutCDRfile <<endl;
       cout <<"PRINT 1::(*j).routecaseName is "<<(*j).routecaseName <<endl;
       cout <<"PRINT 1::(*j).myRouteCaseBasedFileOpen is "<<(*j).myRouteCaseBasedFileOpen <<endl;
       cout <<"PRINT 1::(*j).myRouteCaseBasedFilename is "<<(*j).myRouteCaseBasedFilename <<endl;

  routecaseCDRFile2.routecaseName = "no_routecase_1";
  routecaseCDRFile2.myrouteCaseBasedcdrSeqNumber = 0;
  routecaseCDRFile2.myRouteCaseBasedFileOpen = false;
  routecaseCDRFile2.myCurrentNumOfRecordsWrittenInRouteCaseBasedFile = 0;
  routecaseCDRFile2.myRouteCaseBasedCDRFileSequenceNumber = 0;

  for(vector<routecaseBasedCDRFile>::iterator i=routecaseFileVector.begin();i != routecaseFileVector.end();i++)
        if((*i).routecaseName == "no_routecase_1")
                (*i).myRouteCaseBasedFilename = "/tmp/file2.txt";

 for( vector<routecaseBasedCDRFile>::iterator j=routecaseFileVector.begin();j != routecaseFileVector.end();j++)
       cout <<"PRINT 2::(*j).myRouteCaseBasedOutCDRfile is "<<(*j).myRouteCaseBasedOutCDRfile <<endl;
       cout <<"PRINT 2::(*j).routecaseName is "<<(*j).routecaseName <<endl;
       cout <<"PRINT 2::(*j).myRouteCaseBasedFileOpen is "<<(*j).myRouteCaseBasedFileOpen <<endl;
       cout <<"PRINT 2::(*j).myRouteCaseBasedFilename is "<<(*j).myRouteCaseBasedFilename <<endl <<endl;


  return 0;

The value of myRouteCaseBasedOutCDRfile of the first element of the vector comes out to be different before and after adding the second element. I am not able to understand the reason behind it. And because of changed value, I can not access the file pointed to by it.

Any help would be useful.

Recommended Answers

All 2 Replies

std::ofstream is not a CopyConstructible or CopyAssignable type. But it is MoveConstructible and MoveAssignable.
The CopyConstructor is explicitly deleted.
The CopyAssignment operator is implicitly deleted.

The CopyAssignment operator of routecaseBasedCDRFile wold have been implicitly deleted if had not been declared. In this case, there is a user-defined CopyAssignment operator which does not assign to the std::ofstream member, but copies the state of all the other members, and therefore leaves the object in an invalid state.

Tip: Rule of zero http://en.cppreference.com/w/cpp/language/rule_of_three

#include <iostream>
#include <fstream>
#include <fstream>
#include <vector>
#include <type_traits>

struct A // MoveConstructible, MoveAssignable, not CopyConstructible, not CopyAssignable
    explicit A( std::string path ) : file(path) {}
    A( std::ofstream&& stm ) : file( std::move(stm) ) {} // transfer ownership of the stream

    void test_it() { file << "output from A #" << id << '\n' ; }

    std::ofstream file ; // std::ofstream is Moveable, but it is not Copyable
    // copy constructor of A is implicitly deleted
    // move constructor of A is implicitly defaulted
    // copy assignment of A is implicitly deleted
    // move assignment of A is implicitly defaulted

    int id = seq_no++ ;
    static int seq_no ;

int A::seq_no = 0 ;

int main()
    std::cout << std::boolalpha
              << "MoveConstructible? " << std::is_move_constructible<A>::value << '\n'
              << "CopyConstructible? " << std::is_copy_constructible<A>::value << '\n'
              << "MoveAssignable? " << std::is_move_assignable<A>::value << '\n'
              << "CopyAssignable? " << std::is_copy_assignable<A>::value << "\n\n" ;

    std::vector<A> seq ;

    seq.emplace_back( "out0.txt" ) ;
    seq.push_back( std::ofstream( "out1.txt" ) );

    std::ofstream file( "out2.txt" ) ;
    seq.emplace_back( std::move(file) ) ;

    for( A& a : seq ) a.test_it() ;

    A object( "out3.txt" ) ;

    // seq.push_back( object ); // *** error: call to implicitly-deleted copy constructor of 'A'
                                //      note: ... implicitly deleted because field 'file' has a deleted copy constructor

    seq.push_back( std::move(object) ); // MoveConstructible
    seq.back().test_it() ;

    seq.back() = A( "out4.txt" ) ; // MoveAssignable
    seq.back().test_it() ;

    A object2( "out5.txt" ) ;

    // seq.front() = object2 ; // *** error: ... copy assignment operator is implicitly deleted 
                               //      note: ... implicitly deleted because field 'file' has a deleted copy assignment operator

    seq.front() = std::move(object2) ; // MoveAssignable
    seq.front().test_it() ;

    using std::swap ;
    swap( seq.front(), seq.back() ) ; // Moveable
    for( A& a : seq ) a.test_it() ;


Part of the practical upshot of what vijayan121 is saying here is that you should always pass stream objects (or any other non-copyable objects) by explicit reference (that is, using the reference operator, &) rather than by a pointer reference or by value.

Actually, this is a gross oversimplification, but it is the easiest rule to follow until you have a better understanding of the actual mechanics involved (see the Abelson example at the end of the 'Real Life' section on that page for a clear explanation of why this sort of approach can be useful in a CS context).

On a related note, you will notice that the code example does not use the using namespace directive. This is an important issue, for a number of reasons, but the main one is namespace control. As a general rule the using namespace directive should be avoided in any but the simplest programs; the main purpose of namespaces is to prevent name collisions between different modules, and the using namespace directive subverts that goal. It is better as a rule to either explicitly scope cross-namespace references using the scoping operator, as vijayan121 does here, or to scope the individual elements you are using, like so:

using std::cout;

Explicit scoping is always preferred, but since it can get awkward, the element-specific using directive is acceptable, in most cases, as long as it isn't abused (which is something of a judgement call). This is especially true for header files - you should never have a using or using namespace directive in a header file, as it would get propagated to every file that includes it, which can lead to unexpected namespace collisions.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.