Как заставить "фабричную функцию" возвращать не копируемый объект?

контекст

Пытаясь создать какой-нибудь архив gzip с другим именем внутри, я написал следующий фрагмент кода.

#include <iostream>
#include <utility>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>

boost::iostreams::filtering_ostream&& makeGZipStream(const std::string& archiveName,
                                                     const std::string& fileName)
{
    boost::iostreams::filtering_ostream theGzipStream;

    boost::iostreams::gzip_params theGzipParams;

    theGzipParams.file_name = fileName;

    theGzipStream.push(boost::iostreams::gzip_compressor{theGzipParams});

    theGzipStream.push(boost::iostreams::file_sink{archiveName});

    return std::move(theGzipStream);
}

int main()
{
    boost::iostreams::filtering_ostream&& theGzipStream = makeGZipStream("archive.gz", "file");

    theGzipStream << "This is a test..." << std::endl;

    return 0;
}

проблема

Это (как мы можем ожидать) создает дамп ядра, потому что в makeGZipStream мы пытаемся вернуть локальную переменную, выделенную стеком, по ссылке (rvalue-). Но копия не была вариантом в этом случае, так как boost::iostreams::filtering_ostream не подлежит копированию.

Вопросы

  1. Мы можем вернуть std::unique_ptr "по значению" благодаря конструктору перемещения (а перемещение не должно происходить даже в C++17 благодаря разрешению копирования), почему это невозможно в этом случае?
  2. Какие там хорошие решения?

Возможные решения

  1. Поместить все в одну область (чего я пытался избежать)
  2. Обернуть ваш объект в unique_ptr (не так красиво)
  3. Что-нибудь еще?

Заметки

Компилятор был довольно старый g++ (GCC) 4.9.3,

1 ответ

Решение

Просто верните по значению и удалите std::move() из декларации возврата:

boost::iostreams::filtering_ostream makeGZipStream(const std::string& archiveName,
                                                     const std::string& fileName)
{
    ...
    return theGzipStream;
}

если он не скомпилируется из-за отсутствующего конструктора перемещения, то вам не повезло, и этот тип не может быть перемещен, поэтому поместите его в std::unique_ptr и вернуть этот указатель по значению (которое является подвижным наверняка).

Другие вопросы по тегам