12
votes

I have the following simple class:

class Source
{
public:
    Source() = default;
    Source(Source const&) = delete;
    Source(Source&&) = default;

    explicit Source(std::string const& fileName)
     : inputStream(fileName), path_(fileName)
    {}

    ~Source() = default;

    auto path() const -> std::string
    {
        return this->path_;
    }

    std::ifstream inputStream;
private:
    std::string path_;
};

auto main(int argc, char* argv[]) -> int
{
    Source source(Source("test.txt"));
    cout << source.path() << "\n";

    return 0;
}

According to cppreference ifstream has a move constructor, but when I try to compile that with MinGW 4.7.2, I get the following error:

..\src\main.cpp:32:46: error: use of deleted function 'cy::Source::Source(cy::Source&&)' In file included from ..\src\main.cpp:10:0: source.hpp:28:5: note: 'cy::Source::Source(cy::Source&&)' is implicitly deleted because the default definition would be ill-formed: source.hpp:28:5: error: use of deleted function 'std::basic_ifstream::basic_ifstream(const std::basic_ifstream&)' c:\mingw\bin../lib/gcc/mingw32/4.7.2/include/c++/fstream:420:11: note: 'std::basic_ifstream::basic_ifstream(const std::basic_ifstream&)' is implicitly deleted because the default definition would be ill-formed: c:\mingw\bin../lib/gcc/mingw32/4.7.2/include/c++/fstream:420:11: error: use of deleted function 'std::basic_istream::basic_istream(const std::basic_istream&)'

Am I doing something wrong? Or the documentation of cppreference is inaccurate? Or GCC 4.7.2 has a bug?

2
Move constructor is not deleted, copy-constructor is deleted.Nawaz
Try Source source(Source("source.txt")); Even though your current code is equivalent, I believe there is a requirement that the operator= be accessible or something.Seth Carnegie
@SethCarnegie, thanks for your tip, but it didn't work either, gcc still says that move constructor is implicitly deleted.Rayniery
It just hasn't been implemented yet, see here. All the streams are Missing move and swap operations.Jesse Good
Using a std::unique_ptr<std::ifstream> is one workaround.Jesse Good

2 Answers

12
votes

It turns out that the standard library implementation of GCC has not implemented yet the move and swap operation for the stream classes. See here for detail about the current status of C++11 features in the gcc standard library.

Thanks Jesse Good for giving the information and link.

1
votes

I realise this answer is a little bit late but to give an unmoveable class move sematics you could write a very simple wrapper class. For example:

#include <memory>



template <typename T>
class swap_wrapper
{
    //! internal buffer to hold object (on heap)
    std::unique_ptr<T> p_obj;
public:
    //! allows any of objects constructors to be called directly
    template <typename... Args>
    explicit swap_wrapper(Args&&... args)
        :   p_obj(
                     new T( std::forward<Args>(args)... )
                     ) {    }

    //! swaps pointer value of T object is unchanged therefore this 
    //! function puts no requirement on base class.

    //! note p_obj is left as a nullptr so dereferencing will cause
    //! undefined behaviour.
    swap_wrapper (swap_wrapper &&other) noexcept
        : p_obj(nullptr)
    {
        swap(other);
    }

    //! swaps pointer like above,
    //! T object is not touched; just the pointer.
    swap_wrapper &operator = (swap_wrapper &&other) noexcept
    {
        swap(other);
        return *this;
    }

    //! uses swap member function of std:unique_ptr
    void swap(swap_wrapper &other) noexcept
    {
        std::swap(p_obj, other.p_obj);
    }

    //! operators to allow access to stream
    T& operator *() { return *p_obj; }
    T const& operator *() const { return *p_obj; }

    T * operator ->() { return p_obj.get(); }
    T const * operator ->() const { return p_obj.get(); }

};


//! overload of default swap (calls member function swap)
template <typename S>
inline void swap(swap_wrapper<S> &one, swap_wrapper<S> &two) noexcept
{ one.swap(two); }

This wrapper can then be returned from functions, passed as an rvalue parameter, etc..