Является ли конструктор перемещения ifsteam неявно удаленным?
У меня есть следующий простой класс:
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;
}
Согласно cppreference ifstream
имеет конструктор move
, но когда я пытаюсь скомпилировать его с помощью MinGW 4.7.2
, я получаю следующую ошибку:
..\src\main.cpp: 32: 46: ошибка: использование удаленной функции 'cy:: Source:: Source (cy:: Source &)' В файле, включенном в.. \src\main.cpp: 10: 0: source.hpp: 28: 5: note: 'cy:: Source:: Source (cy:: Source &)' неявно удаляется, поскольку определение по умолчанию будет плохо сформировано: source.hpp: 28: 5: ошибка: использование удаленная функция 'std:: basic_ifstream:: basic_ifstream (const станд:: basic_ifstream &) "C:\MinGW\бен../Library/GCC/mingw32/4.7.2/включить/С++/fstream: 420: 11: note: 'std:: basic_ifstream:: basic_ifstream (const std:: basic_ifstream &) 'неявно удаляется, поскольку значение по умолчанию определение будет плохо сформировано: C:\MinGW\бен../Library/GCC/mingw32/4.7.2/включить/С++/fstream: 420: 11: Ошибка: использование удаленной функции" Станд:: basic_istream:: basic_istream (Const станд:: basic_istream &)
Я что-то делаю неправильно? Или документация cppreference неточна? Или у GCC 4.7.2 есть ошибка?
Ответы
Ответ 1
Оказывается, что стандартная реализация библиотеки GCC еще не реализовала операцию перемещения и свопинга для классов потоков. См. здесь для подробностей о текущем состоянии функций С++ 11 в стандартной библиотеке gcc.
Спасибо Jesse Good за предоставленную информацию и ссылку.
Ответ 2
Я понимаю, что этот ответ немного запоздал, но чтобы дать невозмутимую семантику перемещения класса, вы могли бы написать очень простой класс-оболочку. Например:
#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); }
Затем эту оболочку можно вернуть из функций, переданных как параметр rvalue и т.д.