【问题标题】:How to have "factory function" return a non copyable object? [duplicate]如何让“工厂函数”返回不可复制的对象? [复制]
【发布时间】:2018-12-28 22:03:27
【问题描述】:

上下文

尝试在其中创建一些具有不同文件名的 gzip 存档,我在以下 sn-p 代码中编写了此代码。

#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. 我们可以 return a std::unique_ptr "by value" 感谢它的移动构造函数(由于复制省略,移动甚至不应该在 C++17 中发生),为什么在这种情况下不可能?
  2. 那里有什么好的解决方案?

可能的解决方案

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

注意事项

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

【问题讨论】:

  • @SergeyA 是的,问题中已经提到了。
  • @matovitch 如果您使用 return std::move(theGzipStream); 并且它仍然报错,请确保您的类型具有移动构造函数。
  • @matovitch 您的问题实际上是不正确的。它适用于unique_ptrs 不是因为复制省略,而是因为移动构造函数
  • @matovitch 那么您的类型既不可复制又不可移动。它永远不能按值返回。最简单的解决方法可能是将其包装在 unique_ptr 中。
  • @matovitch,没关系,它在语义上仍然相同。如果没有移动构造函数,unique_ptr 将无法从函数返回(不包括 C++ 17 复制省略)。

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


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 2019-10-13
    • 1970-01-01
    • 2018-08-10
    • 2014-12-10
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2021-04-03
    • 1970-01-01
    相关资源
    最近更新 更多