2013-02-28 69 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引用,并且您正在传递一个临时对象,该对象最好只能发送给一个const引用参数。为了回答你的第二个问题,不编译/工作的代码几乎不符合“好风格”的传说。 – WhozCraig 2013-02-28 01:54:31

+0

第二个版本如何失败?它是否编译?如果不是,那么错误是什么?如果是这样,你是否会遇到运行时错误? – 2013-02-28 01:54:31

回答

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 2013-02-28 02:00:11

+2

这在C++ 03中是正确的。在C++ 11中,可以将临时对象作为非const * rvalue引用*传递。 – 2013-02-28 02:00:57

+1

@BenVoigt:我知道,但我仍然没有将自己的头围绕右值引用,而且我更喜欢不谈论我不知道的东西。 – 2013-02-28 02:02:13

0

我从我的编译器中得到了下面的错误信息,它解释了它。

std::ostream_iterator的构造函数接受非const引用。没有一个版本的构造函数需要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'派生,该''应该转换。它不会转换,因为右值不能绑定到非常量左值引用。 – pmr 2013-02-28 02:28:10

0

在C++中,我们也经常构建对象,但需要注意所有权问题。

ostream_iterator<int>(ofstream("my_file.txt"))的问题在于临时对象正在传递给构造函数,但构造的ostream_iterator对象并不拥有临时职责的所有权。如果ostream_iterator也不是临时的,它将在下一行代码中继续保留无效的引用。

有办法解决这个问题,通过传递给身份函数或铸造。但是他们通常会牺牲安全性,因为如果你在一个持久变量上使用这种机制,它会创建一个悬空参考。

当您有几个对象通过引用链接而没有容器包含关系时,当前C++最佳做法是使用命名对象,而不是临时对象。

如果你不喜欢这样,你可以选择更频繁地使用共享指针。该模式允许在几个引用之间共享所有权,并将容器隐藏起来。但这不是iostreams的一部分,并且作为设计决定,这里有点可疑。