首页 > 解决方案 > 如何让“工厂函数”返回不可复制的对象?

问题描述

语境

尝试在内部创建一些具有不同文件名的 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我们尝试通过(右值)引用返回本地堆栈分配的变量。但是在这种情况下,副本不是一个选项,因为boost::iostreams::filtering_ostream它是不可复制的。

问题

  1. 由于它的移动构造函数,我们可以返回一个std::unique_ptr“按值”(由于复制省略,移动甚至不应该在 C++17 中发生),为什么在这种情况下不可能呢?
  2. 那里有什么好的解决方案?

可能的解决方案

  1. 将所有内容放在同一范围内(我试图避免的)
  2. 将您的对象包装在一个unique_ptr(不太漂亮)中
  3. 还要别的吗 ?

笔记

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

标签: c++c++11move-semanticscopy-elisionnoncopyable

解决方案


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

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

如果由于缺少移动构造函数而无法编译,那么您很不走运并且这种类型不可移动,因此将其包装std::unique_ptr并按值返回该指针(这肯定是可移动的)。


推荐阅读