【发布时间】:2011-09-25 08:56:35
【问题描述】:
我需要有关[io](f)streams 不可复制性质的帮助。
我需要在fstreams 周围提供一个hackish 包装器,以便在Windows 上处理文件名中包含Unicode 字符的文件。为此,我设计了一个包装函数:
bool open_ifstream( istream &stream, const string &filename )
{
#ifdef __GLIBCXX__
FILE* result = _wfopen( convert_to_utf16(filename).c_str(), L"r" );
if( result == 0 )
return false;
__gnu_cxx::stdio_filebuf<char>* buffer = new __gnu_cxx::stdio_filebuf<char>( result, std::ios_base::in, 1 );
istream stream2(buffer);
std::swap(stream, stream2);
#elif defined(_MSC_VER)
stream.open( convert_to_utf16(filename) );
#endif
return !!stream;
}
std::swap 当然是罪魁祸首。我也尝试从函数返回流,但它会导致同样的问题。 std::istream 的复制构造函数是 deleted。我也尝试了std::move,但这并没有帮助。我该如何解决这个问题?
编辑:感谢@tibur 的想法,我终于找到了Keep It Simple (TM) 的好方法,而且功能强大。从某种意义上说它仍然是 hackish,因为它依赖于所使用的 Windows 标准 C++ 库,但由于只有两个 真正的 库在使用,所以这对我来说不是问题。
#include <fstream>
#include <memory>
#if _WIN32
# if __GLIBCXX__
# include<ext/stdio_filebuf.h>
unique_ptr<istream> open_ifstream( const string &filename )
{
FILE* c_file = _wfopen( convert_to_utf16(filename).c_str(), L"r" );
__gnu_cxx::stdio_filebuf<char>* buffer = new __gnu_cxx::stdio_filebuf<char>( c_file, std::ios_base::in, 1 );
return std::unique_ptr<istream>( new istream(buffer) );
}
# elif _MSC_VER
unique_ptr<ifstream> open_ifstream( const string &filename )
{
return unique_ptr<ifstream>(new ifstream( convert_to_utf16(filename)) );
}
# else
# error unknown fstream implementation
# endif
#else
unique_ptr<ifstream> open_ifstream( const string &filename )
{
return unique_ptr<ifstream>(new ifstream(filename) );
}
#endif
在用户代码中:
auto stream_ptr( open_ifstream(filename) );
auto &stream = *stream_ptr;
if( !stream )
return emit_error( "Unable to open nectar file: " + filename );
这取决于 C++0x <memory> 和 auto 关键字。当然,您不能只使用close 生成的stream 变量,而是GNU Libstdc++ std::istream 析构函数会负责关闭文件,因此在任何地方都不需要额外的内存管理。
【问题讨论】:
-
你为什么要通过 iostreams 推送一个 UTF-16 字符串?首先,我不认为 _wfopen 需要一个 UTF-16 字符串。我相当确定,在基于 GCC 的编译器上,wchar_t 字符串应该是 UTF-32。由于 wchar_t 的长度为 32 位,这与 Visual Studio 下的长度为 16 位不同。其次,您确定不能只向他们传递 UTF-8 字符串吗?诚然,我不知道 GCC 的标准 C++ 库是如何在 Windows 上实现的,但在 UNIX 上,它们采用 UTF-8 字符串。所以我希望他们在幕后为您进行转换。
-
为什么不将文件名与程序逻辑的其余部分分离,并为使用
GetShortPathName的 Windows 提供一个包装器——这样您就可以将所有文件名统一视为char*。 -
@Nicol:UTF-16 是 Win32 API 的工作方式,Windows 上的 GCC 遵循这一点,与其他原生 Windows 东西兼容。
-
你不需要
fclose()吗?根据文档“当 stdio_filebuf 关闭/销毁时,FILE*不会自动关闭。”
标签: c++ c++11 copy-constructor istream deleted-functions