1

I would like to add an open ofstream as a class (Barcode) attribute. The goal is to implement several Barcodes in my main() that will each be able to write into a specific file. Also, I decided to stock all the barcodes in a vector, which belongs to a Barcodes class, although it is maybe not useful.

Here is my code:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sys/stat.h>

using namespace std;

class Barcode {
    public:
        // Constructor
        Barcode(string bcName, string bcSeq, string end, string const & fileName): 
            m_bcName(bcName), m_bcSeq(bcSeq), m_end(end), m_ofStream(fileName.c_str(), ios::app) {}

        // Getters
        string getBCName() const {
            return m_bcName;
        }        
        string getBCSeq() const {
            return m_bcSeq;
        }

        //setter
        void reportRead(string toReport) {
            m_ofStream << toReport;
        }

    private:
        string m_bcName;
        string m_bcSeq;
        string m_end;
        ofstream m_ofStream;
};


class Barcodes {
    public:
        // Constructor
        Barcodes(string barcodesFile, string end): m_barcodesFile(barcodesFile), m_end(end) {
            initializeBarcodes();  
        }

        // Getters
        vector<Barcode> getBCs() {
            return m_barcodes;
        }

        // Other
        void initializeBarcodes() {
            ifstream flow(m_barcodesFile);
            if(!flow) {
                cerr << "ERROR: Could'n find the \"barcode.txt\" file." << endl;
            }

            else {
                string line, name, seq;
                // parse each line of the barcode file
                while(getline(flow, line)) {
                    //get the name and sequence of the barcodes
                    name = line.substr(0, 4);
                    seq = line.substr(5, 6);

                    //create the corresponding Barcode
                    string fileName = "Demultiplexed_Reads/" + name + "." + m_end + ".fastq";
                    Barcode bc(name, seq, m_end, fileName);
                    //add them in the corresponding vector
                    m_barcodes.push_back(bc);
                }
            }
        }

    private:
        string m_barcodesFile;
        string m_end;
        vector<Barcode> m_barcodes;
};

int main(int argc, char* argv[]) {

    //Create a new "Demultiplexed_Reads" folder
    system("rm -rf Demultiplexed_Reads");
    if(mkdir("Demultiplexed_Reads", 0755) != 0) {
        cerr << "ERROR: Couldn't create the Demultiplexed folder." << endl;
        return 1;
    }

    else {

        // Get the files to demultiplex
        string f1 = argv[1];
        string f2 = argv[2];

        // Generate the vectors of barcodes
        Barcodes bcs1("barcodes.txt", "end1");
        vector<Barcode> barcodes1(bcs1.getBCs());
        Barcodes bcs2("barcodes.txt", "end2");
        vector<Barcode> barcodes2(bcs2.getBCs());

        // Demultiplex the reads of the end1
        Demultiplexer dm1(f1, barcodes1, "end1");
        dm1.demultiplex();
        cout << "Reads of end1 demultiplexed" << endl;

        // Demultiplex the reads of the end2
        Demultiplexer dm2(f2, barcodes2, "end2");
        dm2.demultiplex();
        cout << "Reads of end2 demultiplexed" << endl;    

        return 0;
    }
}

However, I encounter errors that I don't understand about deleted methods when I am trying to compile g++ --std=c++11 myProg.cpp -o myProg:

In file included from /usr/include/x86_64-linux-gnu/c++/5/bits/c++allocator.h:33:0,
                 from /usr/include/c++/5/bits/allocator.h:46,
                 from /usr/include/c++/5/string:41,
                 from /usr/include/c++/5/bits/locale_classes.h:40,
                 from /usr/include/c++/5/bits/ios_base.h:41,
                 from /usr/include/c++/5/ios:42,
                 from /usr/include/c++/5/ostream:38,
                 from /usr/include/c++/5/iostream:39,
                 from Demultiplex.cpp:1:
/usr/include/c++/5/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = Barcode; _Args = {const Barcode&}; _Tp = Barcode]’:
/usr/include/c++/5/bits/alloc_traits.h:530:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = Barcode; _Args = {const Barcode&}; _Tp = Barcode; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<Barcode>]’
/usr/include/c++/5/bits/stl_vector.h:917:30:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = Barcode; _Alloc = std::allocator<Barcode>; std::vector<_Tp, _Alloc>::value_type = Barcode]’
Demultiplex.cpp:85:44:   required from here
/usr/include/c++/5/ext/new_allocator.h:120:4: error: use of deleted function ‘Barcode::Barcode(const Barcode&)’
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^
Demultiplex.cpp:18:7: note: ‘Barcode::Barcode(const Barcode&)’ is implicitly deleted because the default definition would be ill-formed:
 class Barcode {
       ^
Demultiplex.cpp:18:7: error: use of deleted function ‘std::basic_ofstream<_CharT, _Traits>::basic_ofstream(const std::basic_ofstream<_CharT, _Traits>&) [with _CharT = char; _Traits = std::char_traits<char>]’
In file included from Demultiplex.cpp:2:0:
/usr/include/c++/5/fstream:723:7: note: declared here
       basic_ofstream(const basic_ofstream&) = delete;
       ^
In file included from /usr/include/c++/5/vector:62:0,
                 from Demultiplex.cpp:4:
/usr/include/c++/5/bits/stl_construct.h: In instantiation of ‘void std::_Construct(_T1*, _Args&& ...) [with _T1 = Barcode; _Args = {const Barcode&}]’:
/usr/include/c++/5/bits/stl_uninitialized.h:75:18:   required from ‘static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const Barcode*, std::vector<Barcode> >; _ForwardIterator = Barcode*; bool _TrivialValueTypes = false]’
/usr/include/c++/5/bits/stl_uninitialized.h:126:15:   required from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const Barcode*, std::vector<Barcode> >; _ForwardIterator = Barcode*]’
/usr/include/c++/5/bits/stl_uninitialized.h:281:37:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const Barcode*, std::vector<Barcode> >; _ForwardIterator = Barcode*; _Tp = Barcode]’
/usr/include/c++/5/bits/stl_vector.h:322:31:   required from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = Barcode; _Alloc = std::allocator<Barcode>]’
Demultiplex.cpp:63:20:   required from here
/usr/include/c++/5/bits/stl_construct.h:75:7: error: use of deleted function ‘Barcode::Barcode(const Barcode&)’
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

Does anybody know what the problem is ?

Thank you so much !

Anoikis
  • 105
  • 1
  • 13
  • 2
    You're trying to copy an `ofstream`, but that's not supported (see this part of your error message: `basic_ofstream(const basic_ofstream&) = delete;`). I've just scanned your code, but this is probably because of your `getBc` function. – Stephen Newell May 06 '18 at 19:05
  • 1
    See https://stackoverflow.com/a/6010930/5111904 why copying a `stream` doesn't make sense. The copy constructor is implicitly deleted because the default copy constructor would try to create a copy of the `ofstream` – Matthias Herrmann May 06 '18 at 19:10
  • Does it mean that I can fix my code with references ? In this case, where should I put them ? – Anoikis May 06 '18 at 19:18
  • You could just overload the `<<` operator for the `Barcode` class than it doesn't matter if you write to `stdout` or to a file. What value does `string toReport` contain ? You never call it... – Matthias Herrmann May 06 '18 at 19:26
  • It contains a long string. I don't call it in this code because I was just checking that my `Barcode` and `Barcodes` class work. The end of my `main` should feed strings to the reportRead method... hopefully. – Anoikis May 06 '18 at 19:42

1 Answers1

0

So I found a way to overcome my problem so I just write the solution I used here in case it would be useful for somebody.

Finally, I created a vector of ofstreams in the method that write into output files instead of putting the streams in the objects. I did it just before the loop that reads ans sorts lines from the input file.

As you said, the trick is no to try to copy the stream since it is not possible. But their reference can be moved into the vector. So I used the move function, which is in the standard since C++11:

ofstream ofs(fileName);
ofStreams.push_back(move(ofs));

I worked for me and allowed my program to be way faster than opening a stream and closing it for every line that I need to sort.

Anoikis
  • 105
  • 1
  • 13
  • There is no storing of a "reference" here; you are _moving_ `ofs` into the container. The new ofstream in the container is "move constructed" from `ofs`. I can't quite tell what your question is about, and this solution may be what you need, but be careful not to use `ofs` again afterwards (unless you reset it) – Lightness Races in Orbit May 07 '18 at 13:08