【问题标题】:c++ problems with temporary ostream objects临时ostream对象的c ++问题
【发布时间】:2013-02-14 02:04:57
【问题描述】:

我想转换这个工作代码:

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 背景,一直在动态创建对象。

谢谢!!

【问题讨论】:

  • 因为迭代器的构造函数需要非 const 引用,并且您正在传递一个临时对象,最多只能将其发送到 const 引用参数。要回答您的第二个问题,无法编译/工作的代码几乎不符合“良好风格”的传说。
  • 第二个版本怎么失败了?它编译吗?如果不是,错误是什么?如果是这样,您会收到运行时错误吗?

标签: c++ temporary-objects anonymous-objects


【解决方案1】:

ostream_iterator&lt;T&gt; 构造函数采用非const 引用 到流对象,而临时对象最多可以作为const 引用传递(至少在C++03 中); this question 很好地解释了这样做的理由。

顺便说一句,这里没有太多关于如何传递流的选择:const 引用没有意义(ostream_iterator 具有 来修改流) , 而普通的 ostream 是不可接受的,因为它是不可复制的(切片会杀死多态性)。

在 Python 中,您可以随时构建/传递东西,因为您总是在处理 referencesreference-counted(和垃圾收集)对象

C++ 对象语义完全不同——对象对象,而不是引用;要获得类似于 Python 的语义,您必须使用 new 动态分配每个对象,并将它们传递给包裹在 shared_ptr&lt;T&gt; 中的对象。

在 C++ 中明确命名是否更好

不一定 - 创建临时对象是完全正常的,但您必须了解您可以对它们做什么和不能做什么,引用如何影响它们的生命周期等。

【讨论】:

  • +1 如果我对此的支持在 cmets 中并不明显。
  • 这在 C++03 中是正确的。在 C++11 中,您可以将临时对象作为非 const 右值引用
  • @BenVoigt:我知道,但我还没有完全理解右值引用,我不想谈论我不太了解的东西。
【解决方案2】:

我从我的编译器收到以下错误消息,解释了它。

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>]

【讨论】:

  • 是的,但是有一个引用 basic_ostreamoftream_iterator 派生自 basic_ostream 应该转换。它不会转换,因为右值不能绑定到非 const 左值引用。
【解决方案3】:

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

ostream_iterator&lt;int&gt;(ofstream("my_file.txt")) 的问题是临时对象被传递给构造函数,但构造的ostream_iterator 对象不具有临时对象职责的所有权。如果ostream_iterator 也不是临时的,它将继续在下一行代码中持有无效引用。

有一些方法可以解决这个问题,通过传递给标识函数或通过强制转换。但是它们通常会牺牲安全性,因为如果您在持久变量上使用这种机制,它将创建一个悬空引用。

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

如果您不喜欢这样,您可以选择更频繁地使用共享指针。该模式允许在多个引用之间共享所有权,并隐藏一个容器。但这不是 iostreams 的一部分,作为设计决策,这里会有点问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-25
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-22
    • 2021-10-24
    • 1970-01-01
    相关资源
    最近更新 更多