2013-02-28 4 views
4

Я думал, чтобы преобразовать этот рабочий код:C++ проблемы с временным ostream объектов

ofstream outfile("my_file.txt"); 
copy(v.begin(), v.end(), ostream_iterator<int>(outfile)); 

в это:

copy(v.begin(), v.end(), ostream_iterator<int>(ofstream("my_file.txt"))); 

Другими словами, я использую "анонимный", или безымянный, версию объект потока.

Два вопроса:

(1) Почему вторая попытка не увенчается успехом?

(2) Является ли вторая попытка даже хорошей стилистикой или лучше на C++ сохранить все явно названное? Я исхожу из фона Python, где объекты создаются «на лету» все время.

Спасибо!

+2

Поскольку для конструктора итератора требуется не-const-ссылка, и вы передаете объект temp, который лучше всего может быть отправлен только для параметра const-reference. Чтобы ответить на ваш второй вопрос, код, который не компилируется/работает, вряд ли квалифицируется в легенде «хорошего стиля». – WhozCraig

+0

Как не работает вторая версия? Скомпилирует ли он? Если нет, то какая ошибка? Если да, получаете ли вы ошибку во время выполнения? –

ответ

3

ostream_iterator<T> конструктор принимает не- constссылка на объект потока, в то время как временные конструкции могут быть переданы в качестве наиболее const ссылок (по крайней мере в C++, 03); обоснование для этого хорошо объяснено в this question.

Кстати, здесь не было большого выбора о том, как передать поток: а const ссылка не будет иметь смысл (ostream_iteratorимеет для изменения потока), и простой ostream не приемлемо, потому что оно не копируется (срез убьет полиморфизм).

В Python вы можете уйти с построением/передавая материал на лету, потому что вы всегда имеете дело с ссылки на ссылочных подсчетом (и сборку мусора) объектов.

Семантика объекта C++ радикально отличается - объект является объектом, а не ссылкой; для получения семантики, подобной Python, вам нужно будет динамически распределять каждый объект с помощью new и передавать их, завернутый в shared_ptr<T>.

это лучше в C++, чтобы держать все в явном виде с именем

Не обязательно - это совершенно нормально для создания временных объектов, но вы должны быть осведомлены о том, что вы можете и не можете делать с ними, как ссылки влияют их срок службы и т. д.

+0

+1 В случае, если моя поддержка этого не была очевидна в комментариях. – WhozCraig

+2

Это было верно в C++ 03. В C++ 11 вы можете передавать временные данные как неконстантные * rvalue-ссылки *. –

+1

@BenVoigt: Я знаю, но я все еще не обмотал голову ссылками на ссылки rvalue, и я предпочитаю не говорить о вещах, которые я плохо знаю. –

0

Я получаю следующее сообщение об ошибке от моего компилятора, который объясняет это.

Конструктор std::ostream_iterator принимает неконтактную ссылку. Нет версии конструктора, который принимает std :: ofstream.

Untitled 33.cpp:21: error: no matching function for call to ‘std::ostream_iterator<int, char, std::char_traits<char> >::ostream_iterator(std::ofstream)’ 
/usr/include/c++/4.2.1/bits/stream_iterator.h:185: note: candidates are: std::ostream_iterator<_Tp, _CharT, _Traits>::ostream_iterator(const std::ostream_iterator<_Tp, _CharT, _Traits>&) [with _Tp = int, _CharT = char, _Traits = std::char_traits<char>] 
/usr/include/c++/4.2.1/bits/stream_iterator.h:181: note:     std::ostream_iterator<_Tp, _CharT, _Traits>::ostream_iterator(std::basic_ostream<_CharT, _Traits>&, const _CharT*) [with _Tp = int, _CharT = char, _Traits = std::char_traits<char>] 
/usr/include/c++/4.2.1/bits/stream_iterator.h:169: note:     std::ostream_iterator<_Tp, _CharT, _Traits>::ostream_iterator(std::basic_ostream<_CharT, _Traits>&) [with _Tp = int, _CharT = char, _Traits = std::char_traits<char>] 
+1

Да, но есть один, берущий «basic_ostream» по ссылке, а 'oftream_iterator' происходит от' basic_ostream', который должен преобразовать. Он не преобразуется, потому что rvalue не может связываться с ссылкой на константу lvalue. – pmr

0

В C++ мы также часто строим объекты «на лету», но нужно учитывать проблемы владения.

Проблема с ostream_iterator<int>(ofstream("my_file.txt")) заключается в том, что временный объект передается конструктору, но построенный объект ostream_iterator не принимает на себя ответственность за временные обязанности. Если ostream_iterator также не были временными, он продолжал бы удерживать недопустимую ссылку в следующей строке кода.

Есть способы обойти это, перейдя к функции идентификации или путем литья. Но они, как правило, жертвуют безопасностью, в том смысле, что если вы используете такой механизм для постоянной переменной, он создаст оборванную ссылку.

Если у вас есть несколько объектов, связанных ссылками, без связи с контейнером, то актуальная передовая практика C++ заключается в использовании именованных объектов, а не временных.

Если вам это не нравится, вы можете чаще использовать общие указатели. Этот шаблон позволяет делиться собственностью между несколькими ссылками, при этом контейнер скрывается. Но это не часть iostreams, и в качестве дизайнерского решения здесь было бы немного сомнительно.