Question

I'm writing a branch predictor simulator for my architecture class and I'm having some trouble with getting output working between multiple classes. I'm trying to open up one main ofstream in my main.cpp and the pass it to the constructor of each class for use by the objects. I'm getting a whole bunch of errors in my header file such as:

In file included from main.cpp:4:0:
predictors.h: In constructor â?~ATPred::ATPred(std::ofstream&)â?T:
predictors.h:14:18: error: use of deleted function â?~std::basic_ofstream<char>& std::basic_ofstream<char>::operator=(
const std::basic_ofstream<char>&)â?T

So the errors seem to be in my header file:

#ifndef PREDICTORS_H
#define PREDICTORS_H

#include <string>

// Always Taken
class ATPred{
    private:
            std::ofstream outputFile;

    public:
            // Constructor
            ATPred(std::ofstream& file)
            { outputFile = file; }

            // Deconstructor
            ~ATPred()
            {}

            // Member Functions
            void parseResults(std::string filename);
};

// Always Non-Taken
class ANTPred{
    private:
            std::ofstream outputFile;

    public:
            // Constructor
            ANTPred(std::ofstream& file)
            { outputFile = file; }

            // Deconstructor
            ~ANTPred()
            {}

            // Member Functions
            void parseResults(std::string filename);
};

#endif

I'm not sure where I'm going wrong here, so any help would be greatly appreciated.

Was it helpful?

Solution

The problem here is that you're storing the ofstream value rather than reference. You can make your code work by changing ANTPred (and similarly changing ATPred) as follows:

class ANTPred {
private:
    std::ofstream &outputFile;
public:
    ANTPred(std::ofstream &file) : outputFile(file) {
        // other construction work
    }
};

While I say this will make your code work, it is not necessarily safe. Storing a reference to the ofstream object implicitly assumes that it will outlive all ATPred and ANTPred instances. If the ostream is destroyed first, then the behavior of ATPred and ANTPred instances will be undefined and likely lead to segfaults.

A non-exhaustive list of other options include using raw pointers (leads to same lifetime issues pointed out above), shared pointers (either c++11 std::shared_ptr, boost::shared_ptr or some other shared pointer library), constructing a separate output stream for each object, or passing the output stream to the object instances when they are required to log data.

OTHER TIPS

The standard C++ streams are not copyable, and you're storing the member outputFile by value. You'll have to change this to a reference or pointer.

First - when the body of the constructor runs, all member shall already be initialized. You can only assign to them then on. To initialize members, you need to use member initializer list:

   struct X {
      int i;
      X() : i(42)  // <-- member initiliazer
      { }
   };

Second - streams can't be copied or assigned to.

Your options are

  • have a reference or a pointer to the stream as member
  • have the class initialize the stream itself (you'll constructor will take the parameters that constructor of the stream needs, not another stream)

Stream objects cannot simply be copied and assigned because it doesn't make sense to copy a stream.

You could store a reference (or [smart]pointer) to the stream and make sure the object does not go out of scope as long as your class is around (but be careful about who owns the object).

Anyway, if you are determined, this article provides ways to copy streams, but...

In summary, creating a copy of a stream is not trivial and should only be done if you really need a copy of a stream object. In many cases, it is more appropriate to use references or pointers to stream objects instead, or to share a stream buffer between two streams.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top