通过函数打开流
我需要有关 [io](f)stream
的不可复制性质的帮助。
我需要为 fstream 提供一个 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
的复制构造函数是 delete
d。我还尝试了 std::move
但这没有帮助。我该如何解决这个问题?
编辑:感谢@tibur的想法,我终于找到了一种Keep It Simple (TM)
但又实用的好方法。从某种意义上说,它仍然很黑客,因为它依赖于所使用的 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
和 auto
关键字。当然,您不能只是close
生成的stream
变量,但是GNU Libstdc++ std::istream
析构函数确实负责关闭文件,因此任何地方都不需要额外的内存管理。
I need help with the non-copyable nature of [io](f)stream
s.
I need to provide a hackish wrapper around fstream
s in order to handle files with unicode characters in their filenames on Windows. For this, I devised a wrapper function:
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;
}
With of course the std::swap
line being the culprit. I also tried returning the stream from the function, but it leads to the same problem. The copy constructor of a std::istream
is delete
d. I also tried a std::move
but that didn't help. How do I work around this problem?
EDIT: I finally found a good way to Keep It Simple (TM)
and yet functional, thanks to @tibur's idea. It's still hackish in the sense that it depends on the Windows Standard C++ library used, but as there's only two real ones in use, it's not really a problem for me.
#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
And in user code:
auto stream_ptr( open_ifstream(filename) );
auto &stream = *stream_ptr;
if( !stream )
return emit_error( "Unable to open nectar file: " + filename );
Which depends on C++0x <memory>
and the auto
keyword. Of course you can't just close
the resulting stream
variable, but the GNU Libstdc++ std::istream
destructor does take care of closing the file, so no extra memory management is required anywhere.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
怎么样:
What about:
难道不能直接使用
rdbuf
成员函数来设置stream
的缓冲区吗?Couldn't you just use the
rdbuf
member function to setstream
's buffer directly?这是一个不太侵入性的想法:
用法:
Here's a moderately unintrusive idea:
Usage:
我建议一个小的改进:使用
_wopen
(或_wsopen_s
)而不是_wfopen
。您将获得一个文件描述符 (int
),您可以将其传递给stdio_filebuf
以代替FILE*
。通过这种方式,您应该避免泄漏任何资源(如 marcin 所指出的)I would suggest a small improvement: use
_wopen
(or_wsopen_s
) instead of_wfopen
. You will get a file descriptor (int
) that you can pass to thestdio_filebuf
in place of the theFILE*
. In this way you should avoid leaking any resource (as pointed out by marcin)