【问题标题】:C++ Pass by Reference and Value and Const IssuesC++ 通过引用传递和值和常量问题
【发布时间】:2014-08-02 07:01:20
【问题描述】:

我有以下通用代码,其中我有一个在某些内存上实现视图的类,可以通过多种方式创建它。用于为一些数据处理功能提供一致的接口。

class CView
{
    ...
    int m_size;
    float *m_data;
};

class CObjectA
{
    ...
    CView m_view;

    const CView View() const { return m_view; } // returned
    CView View() { return m_view; } // returned
};

class CObjectB
{
    ...
    const CView View() const { return CView(.....); } // constructed
    CView View() { return CView(.....); } // constructed
};

void ProcessAdd(CView &dst, const CView &src1, const CView &src2);
void ProcessReverse(CView &dst, const CView &src);
void ProcessMul(CView &dst, const CView &src1, const CView &src2);

现在我想知道View 方法是否应该通过引用或值返回,以及Process 方法是否应该使用引用或值。我想尽量减少复制,但保留执行以下操作的能力:

CObjectA a1, a2;
CObjectB b1;
... init these somehow
ProcessAdd(a1.View(), b1.View(), a2.View());

似乎编译器不允许我让 View() 方法返回一个副本,然后通过引用传递给 Process 函数。

View 对象的重量相当轻,只指向可以读取或修改的数据。

如果View 方法返回CView 而不是CView & 类型,这是否意味着当我将它们传递给Process 函数时会有双重复制?获得所需行为的最有效方法是什么?

另一个问题是实现 const 正确性的正确方法是什么?我实际上从不希望进程函数更改CView 类的成员变量,但我确实希望CView 类中的数据指针指向Process 的第一个参数的非常量数据,即输出视图。如果我按值传递,大概没有 const 限定符?

【问题讨论】:

    标签: c++ constants pass-by-reference pass-by-value


    【解决方案1】:

    您是对的,如果您按值传递,则无需将其设为 const 值。

    要回答您问题的第一部分,如果您返回 CView 并将其传递给流程函数,则不会再次复制它,因为 ProcessAddProcessReverseProcessMul 函数的参数都是参考。它将使用相同的 CView 对象。

    如果您想封装CView 对象,有一些更简洁的方法可能对您的应用程序有意义。例如,您可以将视图方法更改为如下所示:

    const CView& View() const { return m_view; }
    

    然后,如果您对要修改的视图有其他引用,则可以不理会 Process 函数。但是,由于看起来您正在创建结合其他 CViews 的新对象,因此您可以更改函数以直接返回新视图:

    CView ProcessAdd(const CView &src1, const CView &src2);
    

    你能通过价值传递你所有的CViews 吗?大概。您在示例中的类型很小,因此副本可能不会有太大的不同。但是,如果对象有任何重要的指针所有权规则(看起来可能)或者可以扩展以获得更多信息,那么您可能只想从一开始就使用引用。

    【讨论】:

    • 如果 Process 函数参数是按值传递的,CView 对象将被复制两次:一次在 View 方法中,一次在函数调用中,或者编译器足够聪明,不会这样做那个?
    • @Robotbugs 这是一个非常好的问题。我不确定这是否在 C++ 标准中定义,或者它是否未定义。
    • @Robotbugs 你有例子吗?该标准允许实现在各种情况下省略副本,这在大多数流行的编译器/平台组合上得到了很好的实现。但魔鬼在细节中,就像他们那样。
    • @Robotbugs 另外,如果您返回一个值,通常意味着您可以使用该方法 const (除非它需要调用非常量方法来创建该值。)所以在您的情况下,您只需要一个View() 方法CView View() const;,而不是您显示的两个。
    • 其实我相信View这两个方法是必要的,即使它返回一个值。这是因为如果类是 const,我希望它返回一个 const 对象,如果不是,则返回一个非 const 对象。 View 对象的常量性不仅表明View 成员不能更改,而且表明底层内存是只读的。我没有在这里展示它,但是View 对象上的访问方法允许您获取数据,如果View 是 const,则返回一个 const 浮点引用,如果不是,则返回一个浮点引用。因此,如果View 是 const,则防止分配给内存元素。
    猜你喜欢
    • 2011-03-14
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    • 2013-08-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-10
    • 2014-01-18
    相关资源
    最近更新 更多