如何使“工厂功能”返回不可复制的对象?

时间:2018-07-20 14:48:02

标签: c++ c++11 move-semantics copy-elision noncopyable

上下文

尝试创建一些内部使用不同文件名的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. 由于return a std::unique_ptr "by value"的move构造函数,我们可以{{3}}(而且由于复制删除,甚至在C ++ 17中也不应发生移动),为什么在这种情况下不可能呢?
  2. 那里有什么好的解决方案?

可能的解决方案

  1. 将所有内容都放在同一范围内(我试图避免的情况)
  2. unique_ptr(不太漂亮)包装对象
  3. 还有什么?

注释

使用的编译器是相当老的g++ (GCC) 4.9.3

1 个答案:

答案 0 :(得分:5)

只需按值返回并从return语句中删除std::move()

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

如果由于缺少move构造函数而导致编译失败,则说明您不走运,并且该类型不可移动,因此请将其包装到std::unique_ptr中,然后按值返回该指针(肯定是可移动的)。