何时使用引用

When do I use references?

本文关键字:引用 何时使      更新时间:2023-10-16

我对引用的理解是它们是已经存在的变量的别名 - 它们不能为空。它们对于修改原始输入时的函数调用很有用,因为引用被认为比指针更安全。

除了上述情况以及引用是强制性的情况之外,是否有其他原因/用例使用引用而不是引用指向的已经存在的变量

编辑:请注意,除了上述内容之外,我说的还有。这意味着我想知道在调用函数之外,什么时候其他引用有用 - 当不需要时(我已经知道了(。我还特别想知道何时引用优先于原始变量,而不是指针(我已经从另一个问题中学到了"尽可能使用引用,必须使用指针"在两者之间进行选择时

(。

假设你有一个大结构,或者一个std::vector或一个std::string对象,你通过值将其传递给函数。这意味着对象被复制,这对于大型对象(例如数百万个条目的向量(可能非常低效。然后,您可以使用对常量对象的引用,例如 std::vector<SomeType> const& my_object .

我们使用引用是因为以下事情

  1. 修改调用方函数的局部变量。

  2. 用于传递大型参数。

  3. 以避免对象切片。

  4. 在函数中实现运行时多态性。

有关详细信息,请参阅 http://www.geeksforgeeks.org/when-do-we-pass-arguments-by-reference-or-pointer/

尽可能使用引用而不是指针。除非你想操纵低级内存,否则你不应该处理指针。另一种用法是使用 new 作为指针将主要数据保留在堆上,并传递该指针的引用。但是,对于新的unique_ptr,shared_ptr和weak_ptr的组合甚至不需要。唯一需要指针的地方是对象可以是 nullptr 时,因为引用不能为 NULL。您可以放心地假定引用是有效的对象,除非有人以不正当的方式扭曲了代码。

一个

常见的误解是引用比指针更安全,但这是一个误解。生成空引用和其他非法引用同样容易。这些可以在炸毁程序之前传播很远。以下是一些示例:

    创建空引用
  • :只需取消引用空指针即可将结果传递给需要引用的内容。

    class Foo {
        public:
            Foo() : bar(null_ptr) {}
            void setSize(size_t newSize) {
                delete bar;
                bar = new int[newSize];
            }
            doSomething() {
                myVec.push_back(bar[0]);    //This will blow up somewhere in the push_back() implementation, not here!
            }
        private:
            int* bar;
            std::vector<int> myVec;
    };
    void baz() {
        Foo myFoo;
        myFoo.doSomething();
    }
    

    关键是上面的代码不会在你取消引用空指针时爆炸,它只会静默地创建一个空引用。这是合法的,因为取消引用空指针被定义为未定义的行为,而创建空引用是编译器可以执行的有效操作。

    空引用将被成功传递给std::vector<>::push_back(),只有当它本身试图使用引用来实际获取它后面的值时,才会出现段错误。

  • 悬空引用:只需让引用的对象在引用结束其生存期之前结束即可。同样,与指针相同的问题:

    std::vector<int> foo;
    foo->push_back(7);
    int& bar = foo[0];                   //perfectly legal
    bar *= 6;                            //perfectly legal
    foo->push_back(8);                   //perfectly legal
    cout << "The answer is: " << bar;    //BOOM, bar is dangling, undefined behavior results
    

    注意:此代码实际上可能按预期运行,就像访问悬空指针的代码可以按预期重现运行一样。

  • 超出范围的引用:就像使用指针一样容易完成:

    std::vector<int> array;
    array.resize(7);
    int& bar = array[7];    //undefined behavior, even if the compiler detects this, it will silently ignore it
    bar = 42;    //since this is undefined behavior, the compiler may optimize away this line
    

    与悬空引用一样,此代码可能运行良好,但它可能无法执行您认为的功能。由于优化,它甚至可能不会写入超出范围的元素。或者,它可能会损坏堆和/或堆栈,或者静默计算错误的结果。只是用段错误炸毁实际上是这里最不可能的结果。

如您所见,最后两个示例代码甚至不需要任何地方的显式指针,它们仅使用现代、闪亮C++样式的数据结构。然而,它们会导致未定义的行为,这些行为不会在调用它的地方发生。非法引用可能会在明显的坏事开始发生之前从创建它的位置传播到任何距离。这正是人们害怕使用指针的原因;指针和引用的危险是相同的。

所以,真的,在对你有意义的地方使用引用。但不要依赖它们是"安全的"。