повысить провал утверждения iostreams

Мне нужно иметь возможность использовать один Fstream, чтобы иметь независимый от платформы способ использования файлов. В частности, мне нужно иметь возможность поддерживать пути к файлам с символами Unicode в Windows с минимальным вмешательством в код для его поддержки. Таким образом, казалось, что ускорение Iostreams может дать ответ. Однако, пытаясь использовать его, я получаю две ошибки, которые вызывают у меня беспокойство. Смотрите следующий пример кода:

// MinGW (MSYS)
// GCC 4.7.2
// Boost 1.50.0
// g++ -g ifstreamtest.cpp -o test.exe -I /t/tools/boost/boost_1_50_0 -L /t/tools/boost/boost_1_50_0/stage/lib -lboost_system-mgw47-mt-d-1_50 -lboost_filesystem-mgw47-mt-d-1_50 -lboost_locale-mgw47-mt-d-1_50 -lboost_iostreams-mgw47-mt-d-1_50

#include <boost/locale.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/filesystem/path.hpp>

namespace MyNamespace
{

typedef ::boost::iostreams::file_descriptor fd;
typedef ::boost::iostreams::stream< ::boost::iostreams::file_descriptor> fstream;
typedef ::boost::iostreams::stream< ::boost::iostreams::file_descriptor_sink> ofstream;
typedef ::boost::iostreams::stream< ::boost::iostreams::file_descriptor_source> ifstream;
} // namespace MyNamespace

int main(int argc, char **argv)
{
// Imbue boost filesystem codepoint conversions with local system
// Do this to ensure proper UTF conversion.
boost::filesystem::path::imbue(boost::locale::generator().generate(""));

// Test file path.
boost::filesystem::path file_path("test.txt");// Anonymous scope for temporary object.
{
// Open file in ctor, write to output, neglect to clean up until dtor.
MyNamespace::ofstream output(file_path, std::ios_base::out | std::ios_base::app);
if ( output.is_open() == false ) std::cout << "Unable to open @" << __LINE__ << std::endl;
output << "test line 1" << std::endl;
std::cout << "done @" << __LINE__ << std::endl;
}
// Temporary object destroyed while still open.

// Anonymous scope for temporary object.
{
// Open file in ctor, write to output, specifically close file.
MyNamespace::ofstream output1(file_path, std::ios_base::out | std::ios_base::app);
if ( output1.is_open() == false ) std::cout << "Unable to open @" << __LINE__ << std::endl;
output1 << "test line 2" << std::endl;
output1.close();
std::cout << "done @" << __LINE__ << std::endl;
}
// Temporary object destroyed.

// Anonymous scope for temporary object.
{
// Default-ctor; open later. Write to file, neglect to clean up until dtor.
MyNamespace::ofstream output2;
// Next line causes "Assertion failed: initialized_, file t:/tools/boost/boost_1_50_0/boost/iostreams/detail/optional.hpp, line 55"output2->open(file_path, std::ios_base::out | std::ios_base::app);
if ( output2.is_open() == false ) std::cout << "Unable to open @" << __LINE__ << std::endl;
output2 << "blah test test blah" << std::endl;
}
// Temporary object destroyed.

//    MyNamespace::ifstream input;
// Compile success, but linker failure:
// s:\reactor\utf8stream/ifstreamtest.cpp:42: undefined reference to `void boost::iostreams::file_descriptor_source::open<boost::filesystem::path>(boost::filesystem::path const&, std::_Ios_Openmode)'
//    input->open(file_path, std::ios_base::in);

std::cout << "done." << std::endl;
return 0;
}

На Windows я ограничен GCC 4.7.2 и Boost 1.50.

Комментарии объясняют две ошибки, но я остановлюсь на них здесь. Первое и наиболее проблемное для меня — это когда я пытаюсь использовать объект потока в качестве «нормального» объекта fstream. Если я открою fstream в его конструкторе, то все будет хорошо и прекрасно (как видно из первых двух анонимных областей). Но если я выделю объект fstream, а затем попытаюсь открыть его позже, произойдут «плохие вещи».

Если я пытаюсь вызвать boost :: iostreams :: stream :: open (), я получаю ошибки компилятора о том, что он не может преобразовать параметр 1 (boost :: filesystem :: path) в boost :: iostreams :: file_descriptor_sink. Почему это не должно работать, когда его можно создать с помощью boost :: filesystem :: path? В любом случае, попытка вызвать boost :: iostreams :: file_descriptor_sink :: open () с помощью оператора потока -> () проваливает утверждение (как показано в третьей анонимной области). Это довольно зло, так как мне кажется, что оно должно генерировать исключение, а не проваливать утверждение. Неудачное утверждение укажет мне на ошибку в буст-коде.

Второй сбой у меня заключается в том, что typedefed fstream и ofstream, кажется, работают (ну, компилируют и связывают) просто отлично. Но когда я пытаюсь использовать ifstream, я получаю ошибку компоновщика при попытке вызвать ifstream-> open (); Я получаю это на Windows (конфигурация MinGW, как указано выше), а также на OS X 10.8.5 с Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn), Поскольку он компилируется нормально, и единственное различие между ними заключается в том, является ли он источником или приемником … и оба должны иметь возможность открывать файл … это заставляет меня думать, что это также ошибка в boost.

Есть мысли или предложения?

2

Решение

По поводу ошибки компилятора:

Я могу воспроизвести ошибку компоновки в Linux с g ++ и Clang ++, так что это не специфическая проблема Windows (я также использую Boost 1.55.0, поэтому он не специфичен для 1.50).

Я предполагаю, что это вызвано определением шаблона, которое разрешено в заголовочном файле, но не реализовано в источнике / библиотеке.

Решение (только для проблемы со связыванием): вместо

input->open(file_path, std::ios_base::in);

использование

input->open(file_path.string(), std::ios_base::in);

Это позволяет обойти потенциально неверно определенный шаблон с помощью строкового конструктора.

Относительно ошибки утверждения:

Проблема в том, что вам нужно инициализировать file_descriptor_sink отдельно, иначе инициализация iostream не будет обработана должным образом. Используйте этот код:

//We need to initialize the sink separately
boost::iostreams::file_descriptor_sink output2Sink(file_path, std::ios_base::out | std::ios_base::app);
MyNamespace::ofstream output2(output2Sink);
if ( output2.is_open() == false ) std::cout << "Unable to open @" << __LINE__ << std::endl;
output2 << "blah test test blah" << std::endl;

open() не похоже на reset optional это вызывает утверждение.

Тот же метод должен применяться к MyNamespace::ifstream:

boost::iostreams::file_descriptor_source inputSource(file_path, std::ios_base::in);
MyNamespace::ifstream input(inputSource);
//Test reading back what we wrote earlier
std::string inputContent;
input >> inputContent;
//Prints: blah (only the first word is read!)
std::cout << "Read from test.txt: " << inputContent << std::endl;

Также обратите внимание, что не обязательно применять решение, чтобы избежать ошибки компилятора сверху.

С этими изменениями ваша программа работает в моей системе.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector