Я думал, чтобы преобразовать этот рабочий код:
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")));
Другими словами, я использую «анонимную» или безымянную версию объекта ofstream.
Два вопроса:
(1) Почему вторая попытка не удалась?
(2) Является ли вторая попытка даже хорошей стилистически, или лучше в C ++ сохранять все явно именованными? Я пришел из фона Python, где объекты создаются на лету все время.
Спасибо!!
ostream_iterator<T>
конструктор принимает неconst
ссылка к объекту потока, в то время как временные значения могут быть переданы максимально const
ссылки (по крайней мере, в C ++ 03); обоснование этого хорошо объясняется в этот вопрос.
Кстати, здесь не было большого выбора о том, как передать поток: const
ссылка не имела бы смысла ( ostream_iterator
имеет изменить поток), и простой ostream
неприемлемо, потому что это не копируемое (нарезка убила бы полиморфизм).
В Python вы можете с легкостью создавать / передавать вещи на лету, потому что вы всегда имеете дело с Рекомендации в счетчиком ссылок (и сборщик мусора) объекты.
Семантика объекта C ++ радикально отличается — объект является объект, а не ссылка; чтобы получить семантику, аналогичную Python, вы должны динамически распределять каждый объект с помощью new
и передать их, завернутые в shared_ptr<T>
,
лучше ли в C ++ держать все явно названным
Не обязательно — это совершенно нормально для создания временных, но вы должны знать, что вы можете и не можете с ними делать, как ссылки влияют на их жизнь и т. Д.
Я получаю следующее сообщение об ошибке от моего компилятора, которое объясняет это.
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>]
В C ++ мы также часто создаем объекты «на лету», но вопросы владения должны решаться.
Проблема с ostream_iterator<int>(ofstream("my_file.txt"))
является то, что временный объект передается в конструктор, но построенный ostream_iterator
Объект не берет на себя ответственность за временные обязанности. Если ostream_iterator
также не был временным, он продолжал содержать недопустимую ссылку на следующую строку кода.
Есть способы обойти это, перейдя к функции идентичности или путем приведения. Но они, как правило, жертвуют безопасностью, в том смысле, что если вы используете такой механизм для постоянной переменной, это создаст висячую ссылку.
Когда у вас есть несколько объектов, связанных ссылками, без контейнерных отношений, в настоящее время рекомендуется использовать именованные объекты, а не временные.
Если вам это не нравится, вы можете чаще использовать общие указатели. Этот шаблон позволяет разделить владение между несколькими ссылками, при этом контейнер скрыт. Но это не часть iostreams, и как дизайнерское решение это было бы немного сомнительно здесь.