为什么流插入重载中的右操作数必须引用?

时间:2018-02-07 07:32:23

标签: c++

对于C ++插入重载,我们通常会这样做:

ostream& operator<<(ostream& os, X& object){
    // operation
    return os;
}

我的问题是:为什么必须引用X类型的变量对象?

3 个答案:

答案 0 :(得分:3)

  

我的问题是:为什么必须引用变量   X型对象?

您不需要参考,这不是强制性的。在任何情况下,请考虑到,因为您不打算修改 object ,所以最好写成:

ostream& operator<<(ostream& os, const X& object){
    // operation
    return os;
}

简单的替代方法是通过写入:

按值传递 object
ostream& operator<<(ostream& os, X object){
    // operation
    return os;
}

问题出在哪里?您的程序将继续工作,但其性能将受到影响。将指针传递给对象(最终是引用)并不是复制整个对象的效率。想象一下, X 具有以下实现,即它实际上是 GpsTrack 类:

/** A complete track, composed by GpsPoints. */
class GpsTrack {
public:
    /** Creates a new, empty track. */
    GpsTrack()
        {}

    /** Adds a new point to the track.
     *  @param p The new point.
     */
    void add(const GpsPoint &p)
        { gpsPoints.push_back( p ); }       

    /** @return The point at position i. */
    const GpsPoint &operator[](int i)
        { return gpsPoints[ i ]; }

    /** @return The number of points in the track. */
    int size() const
        { return gpsPoints.size(); }

    /** @return A textual representation of the track. */
    std::string toString() const;

    /** Adds support for the << operator. */
    friend std::ostream& operator<<(std::ostream& os, const GpsTrack& track)
        { os << track.toString(); return os; }
private:
    std::vector<GpsPoint> gpsPoints;
};

为了这个例子,我们采取32位机器。每个 GpsPoint 包含一对double,每个存储8个字节,总共16个字节。如果 GpsTrack 包含5000个点,则结果大约为78KB。它由std::vector透明地存储在堆中。

请注意,除了上面给出的实现之外,我们还为operator<<()实现了以下实现。

    /** Adds support for the << operator. */
    friend std::ostream& operator<<(std::ostream& os, GpsTrack track)
        { os << track.toString(); return os; }

然后,为了让 track operator<<()内工作,C ++将复制该对象。 std::vector gpsPoints 将透明地复制到另一个向量中,在堆中复制其信息(在开始时分配并在方法结束时解除分配)。但是,此信息由 GpsPoint 组成,对于最坏的情况(取决于其实现),它将意味着遍历所有点并调用其副本构造函数。这不仅浪费时间,也浪费资源(即记忆)。

您可以将它作为const引用传递,它与指针一样高效,并且作为传值可以安全(不允许修改)。

希望这有帮助。

答案 1 :(得分:1)

无需使用 const 引用,您也可以按值传递。两个版本同样运作良好

ostream& operator<<(ostream& os, const X &object);

ostream& operator<<(ostream& os, X object);

const引用的原因通常与其他函数相同:对于(大)对象,复制(即按值传递)比传递引用更昂贵。

另一个原因:const&即使在没有复制构造函数的情况下也能正常工作。

答案 2 :(得分:0)

好吧,通常我们通过值或const引用传递。这里是来自Microsoft VS2017实现的示例。它通过const引用传递字符串,因此我们避免复制并仍然保证不更改对象。

template<class _Elem,
    class _Traits,
    class _Alloc> inline
    basic_ostream<_Elem, _Traits>& operator<<(
        basic_ostream<_Elem, _Traits>& _Ostr,
        const basic_string<_Elem, _Traits, _Alloc>& _Str)
    {   // insert a string
    return (_Insert_string(_Ostr, _Str.data(), _Str.size()));
    }