代码之家  ›  专栏  ›  技术社区  ›  t.g.

是否有任何特定的情况下,通过值优于C++中的const引用?

c++
  •  6
  • t.g.  · 技术社区  · 15 年前

    我读到他们在概念上是平等的。实际上,有没有这样的情况

    foo(T t) 
    

    foo(const T& t)
    

    ? 为什么?


    事实上,我对两者的区别很感兴趣 按常量参考 由瓦尔

    我曾经认为,在调用案例中,by const ref可以用value替换,因为即使是Herb Sutter和Bjarne都说它们在概念上是相等的,“by ref”(be it const)意味着更快。直到最近,我在某个地方读到,在某些情况下,by val可能会更好地优化。

    那什么时候,怎样?

    15 回复  |  直到 15 年前
        1
  •  11
  •   James Hopkin    15 年前

    内置类型和小对象(如STL迭代器)通常应按值传递。

    这部分是为了增加编译器的优化机会。令人惊讶的是,编译器很难知道引用参数是否是另一个参数或全局参数的别名-它可能必须通过函数多次从内存中重新读取对象的状态,以确保值没有更改。

    这就是C99的原因 restrict

        2
  •  5
  •   Paul Sonier    15 年前

    如果要在本地修改 t (不影响原文)在你的方法主体中(比如在计算某物的过程中),第一种方法是优先的。

        3
  •  2
  •   Matt Dillard    15 年前

    如果正在传递的对象是智能指针(即,它自己进行引用计数),则通过值传递可能更合理。

    不过,到目前为止,我的推理路线存在一个问题——通过传递值,您将失去参数的“常量”。也许您应该使用“by reference”语义。。。

        4
  •  2
  •   Michael Burr    15 年前

    不要忘记,当您处理具有奇怪的复制/分配语义的对象时,有些情况会有所不同。

    auto_ptr<> 这是一个经典的例子——不考虑后果就按价值传递,结果可能会一团糟。

        5
  •  1
  •   no-op    15 年前

    此外,当T是简单类型(int、bool等)时,通常使用foo(tt)。

        6
  •  1
  •   rlbond    15 年前

    另一个没有提到的例子是大量使用该对象。假设您传递一个包含5个整数的结构作为成员。如果你打算大量访问函数中的所有5个函数,那么在某一点上,解引用成本超过了复制成本。但是,您必须运行探查器才能知道这是什么时候。

    不过,我应该指出,像STL容器这样在堆上分配内存的东西,如果可以避免的话,几乎不应该按值传递,因为堆分配比堆栈分配慢得多。

        7
  •  1
  •   Mykola Golubyev    15 年前

    在这种情况下,您没有其他选项,只能按值传递参数。当然,boost可以处理这个问题。但如果没有助推,我们必须按值传递一个值。

    class Test
    {
    public:
        Test()
        {
            std::set<std::string> values;
            values.insert("A");
            values.insert("V");
            values.insert("C");
    
            std::for_each(values.begin(), values.end(), 
                    bind1st(mem_fun(&Test::process), this));
        }
    
    private:
        void process( std::string value )
        {
            std::cout << "process " << value << std::endl;
        }
    };
    
        8
  •  1
  •   dicroce    15 年前

    “按常量引用传递”和“按值传递”在概念上相同的原因是它们都不能修改原始值。

    这就是说,它确实可能会使您的代码速度变慢。在过去,我一直倾向于按值传递,除非我知道这样做是(或将是)性能问题。我可能需要稍微修改一下,将passbyconst引用作为更好的选项。

        9
  •  1
  •   JohnMcG    15 年前

    如果函数最直接的实现涉及到在本地修改参数值,那么按值而不是按常量引用传递它是有意义的

    例如,strcpy的单行版本:

    char *strcpy(char *dest, const char *src)
    {
       while (*dest++ = *src++);
    
       return s1;
    }
    

        10
  •  1
  •   j2.    15 年前

    两个非常具体的案例:

    当您编写具有强异常保证的赋值运算符时,您可以像

    X& X::operator=(const X& orig)
    {
        X tmp(orig);
        swap(this, tmp);
        return *this;
    }
    

    或者,您可以认识到,发生的第一件事是,您制作了一份副本,并将其作为通话的一部分

    X& X::operator=(X tmp)
    {
        swap(this, tmp);
        return *this;
    }
    

    如果您有一个具有所有权语义的智能指针,例如。 auto_ptr 自动检查 他们可能是对的,但有时你不会做出这样的选择。

        11
  •  1
  •   Dan Olson    15 年前

    前者在函数内创建对象的副本。这意味着可以在函数中安全地修改该值。它还意味着发生了对象的完整副本,如果对象很大,这可能是一个问题。

    后者为对象创建别名,并声明不能在对象内修改。不会进行复制,但对函数内对象的每次访问都需要取消引用。编译器为我们解决了这一问题,但知道这一点仍然很重要。

    如果您有一个通常在寄存器中传递的类型,那么这种差异就变得非常重要。例如,在某些平台上,整数、浮点数甚至是4浮点向量。性能方面的考虑表明,您希望对象在寄存器中尽可能长时间地保留,而不将自身写回内存,而传递值使这种情况更可能发生。

    因此,对于基本类型(char、short、int、long、float、double),您应该始终更喜欢按值传递 除非

        12
  •  0
  •   Ryan    15 年前
    1. 如前所述,如果要在函数中复制对象,请选择“按值传递”。
    2. 如果复制T比创建/复制引用便宜,我通常使用传递值,例如T=char,T=short。这里的好处可能取决于平台,在适用的情况下,您可能仍然需要const来帮助优化器。
        13
  •  0
  •   anon anon    15 年前

    有些例程需要一个副本,因此不应通过引用传递。例如,国际象棋程序的移动生成器可能需要(递归地)处理当前位置的副本,而不是实际修改位置的原始实例。

        14
  •  0
  •   Community Sam Holder    7 年前

    this answer . 这是一个 SymLink 答案是肯定的。请在那里投票,如果有:)

        15
  •  0
  •   Bklyn    15 年前

    Boost.CallTraits 是一种鲜为人知但很有用的工具,用于传递参数和结果,对于所讨论的类型来说,这应该是最有效的方法。