11
votes

I'm working with a few HID devices, all of which have classes deriving from the following base class (in main.h):

class HIDDevice {
    public:
        hid_device *device;

        virtual void read(std::fstream)=0;
        virtual void write(std::fstream)=0;
};

Here's one of the device classes deriving from it (device.h):

class MyDevice : public HIDDevice {
    public:
        void read(std::fstream);
        void write(std::fstream);
};

...and a sample of the implementation:

void MyDevice::read(std::fstream file) {
    // Read from card and write to file
    response = send_command(READ_DEVICE);
    file.write((char *)&response[0], response.size());
}

...and the caller:

fstream file (filename, ios::binary | ios::in);
dev->read(file);

When I try and compile, I get the following error:

main.cpp:294:27: error: use of deleted function ‘std::basic_fstream::basic_fstream(const std::basic_fstream&)’
In file included from source/main.cpp:24:0: /usr/include/c++/4.6/fstream:761:11: error: ‘std::basic_fstream::basic_fstream(const std::basic_fstream&)’ is implicitly deleted because the default definition would be ill-formed:

... and I have no idea why, probably because I'm fairly new to C++ and I've done something idiotic.

Changing the arguments back to references (using &), I get the following error:

/main.o:(.rodata._ZTV13MyDevice[vtable for MyDevice]+0x18): undefined reference to `MyDevice::write(std::basic_fstream >&)'

Can anyone help me fix this problem?

4
By the way, I 'm not sure how to correct it but the question title is bad: it's not the stream objects that are deleted, "implicitly deleted" refers to the implicit version of this.Jon
@Jon: maybe we should leave it as is in case someone else uses similar search terms? Don't ask me, though, I'm hardly an expert at C++.Andy E
"closed" rather than "deleted" perhaps? Or even better; "double-closed". Between that and the question body I think your covered.WhozCraig

4 Answers

21
votes

Try tossing those std::fstreams around by reference.

class MyDevice : public HIDDevice {
    public:
        void read(std::fstream&);
        void write(std::fstream&);
};
5
votes

Just for reference, I had the same compiler error, but created it in a different way that wasn't immediately obvious to me. Out of habit I wrote:

auto stream = fstream(output, iOS::out | iOS::binary);

Which, of course, creates a temporary fstream object and copies it to stream. That worked in Xcode 6 using clang, but not for GCC 4.9.2.

3
votes

The HIDDevice method signatures mean that the fstreams are being passed around by value. This in turn means that copies of the original stream objects have to be created at the call site using the copy constructor. It is this copy constructor that has the canonical signature std::basic_fstream::basic_fstream(const std::basic_fstream&).

The compiler is telling you that for some reason (which has to do with the particulars of the basic_fstream implementation your standard library uses) it cannot auto-generate this copy constructor, hence it cannot fulfill your implicit command to make copies of the streams.

As others have already said, the usual modus operandi (which will also prevent the error here) is to pass the arguments by reference instead of by value.

1
votes

&std::fstream as a parameter will pass it around by reference to be used as the same object everywhere. This avoids the implementation trying to create another instance and then closing the stream when the functions end (because the copied object is being destructed).

Make sure you change this in both the declaration and the implementation of the member function (i.e. in the class and where the body is).