【问题标题】:C++ When does it make sense to pass a const struct parameter by value vs. reference?C++ 什么时候通过值与引用传递 const 结构参数才有意义?
【发布时间】:2018-09-08 05:07:50
【问题描述】:

我看到了与此类似的问题,但我想澄清一下...

假设一个基本的 C++ 类:

class MyClass
{
public:
    struct SomeData
    {
        std::wstring name;
        std::vector<int> someValues;
    };

    void DoSomething(const SomeData data);
}

我知道data 将作为const 传递给DoSomething,这没关系,因为该函数不会以任何方式修改data...但我习惯于看到&amp;const 参数指定,以确保它们通过引用传递,例如

void DoSomething(const SomeData& data);

这对我来说似乎更有效率。如果我们省略&amp;,那么data 不是按值传递给DoSomething 吗?我不确定当您可以通过引用传递并避免发生复制时,为什么最好按值传递 const 参数?

【问题讨论】:

    标签: c++ parameters reference constants


    【解决方案1】:

    按值/引用传递和常量正确性是两个不同的概念。但一起使用。

    按值传递

     void DoSomething (SomeData data);
    

    当复制成本较低并且不想保留对外部对象的引用时,使用按值传递。这个函数可以(如果它在一个类中)在某些情况下保留一个指向 this 的指针并拥有自己的副本。

    通过引用传递

    void DoSomething (SomeData& data);
    

    如果您知道这可能会导致复制结构的性能损失,请始终使用按引用传递。在某些情况下,这个函数可以(如果它在一个类中)保持一个指向 this 的指针并指向一个外部对象。保留指向外来对象的指针意味着您应该了解它的生命周期以及该外来对象何时超出范围。更重要的是,对外部对象的更改会出现在您的指针上。

    常量正确性

    void DoSomething (const SomeData data);  // const for local copy
    void DoSomething (const SomeData& data); //  const for callers object
    

    添加const通过值或引用传递意味着这个函数不会改变它。但是没有或没有&amp; 决定了您要尝试添加修改的安全性的对象。 const 在 C++ 文档化 API 方面是一个非常有用的工具,提供编译时安全性,允许更多的编译器优化。

    Read这篇文章。

    【讨论】:

    • 当然,如果创建一个通过值传递的副本比通过引用传递的成本更高或更低,那么存在一个问题。对于简单的情况,使用基于对象及其成员和引用的内存大小的经验法则可能就足够了,但是这些大小是实现定义的(即,可以在编译器之间以一种受限的方式变化) 所以经验法则并不总是有效。如果对象的构造函数或析构函数行为不同,则经验法则也会失效,并增加或减少复制成本。
    【解决方案2】:

    void DoSomething(const SomeData data) 的最大问题是它混淆了接口和实现。从调用者的角度来看,const 并没有改变任何东西。该函数无论如何都会收到一个副本,并且原始对象不会被修改。实现与自己的函数内部副本做什么或不做什么不应该打扰调用者,因此不应该在接口中表达。

    如果不更改副本,const 确实会使实现更加 const-correct,但是将实现细节泄漏到接口中是要付出高昂代价的。我建议不要使用void DoSomething(const SomeData data)

    与往常一样,这里不应高估性能的收益或损失。更多的是关于语义和约定。

    【讨论】:

      【解决方案3】:

      传递const 值对调用者来说主要是信息性的,它表明了意图。这对于使代码易于阅读、理解和维护非常重要。

      如果编译器知道函数没有修改它的参数,它也可以添加一些额外的优化。例如,它可能会导致编译器根本不执行复制。

      【讨论】:

        【解决方案4】:

        这个:

        void DoSomething(const SomeData data);
        

        有点不寻常,因为虽然它不会改变调用者(可以传递 const 或非常量值)的任何内容,但它限制了函数内部可以执行的操作。这样做的价值不大,而且通常不这样做。

        如果值复制成本很高,包括如果它大于目标平台上的大约两个指针,则通过引用传递(无论是否为 const)效率更高。换句话说,如果SomeData 是一个包含两个整数的结构,那么按值传递它可能会更有效。但如果它包含std::map 或一些更大的数据,最好通过引用传递。

        一个例外情况是,如果函数无论如何都要复制值,那么最好按值获取,因为如果调用者允许,值可能会被“移动”而不是复制。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-01-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-09-22
          • 2015-11-14
          • 2013-10-07
          相关资源
          最近更新 更多