What is the difference between references and normal variable handles in C++?

后端 未结 8 795
一生所求
一生所求 2021-01-22 23:33

If C++, if I write:

int i = 0;
int& r = i;

then are i and r exactly equivalent?

相关标签:
8条回答
  • 2021-01-23 00:06

    References are slightly different, but for most intents and purposes it is used identically once it has been declared.

    There is slightly different behavior from a reference, let me try to explain.

    In your example 'i' represents a piece of memory. 'i' owns that piece of memory -- the compiler reserves it when 'i' is declared, and it is no longer valid (and in the case of a class it is destroyed) when 'i' goes out of scope.

    However 'r' does not own it's own piece of memory, it represents the same piece of memory as 'i'. No memory is reserved for it when it is declared, and when it goes out of scope it does not cause the memory to be invalid, nor will it call the destructor if 'r' was a class. If 'i' somehow goes out of scope and is destroyed while 'r' is not, 'r' will no longer represent a valid piece of memory.

    For example:

    class foo
    {
    public:
      int& r;
      foo(int& i) : r(i) {};
    }
    
    void bar()
    {
      foo* pFoo;
    
      if(true)
      {
        int i=0;
        pFoo = new foo(i);
      }
    
      pFoo->r=1; // r no longer refers to valid memory
    }
    

    This may seem contrived, but with an object factory pattern you could easily end up with something similar if you were careless.

    I prefer to think of references as being most similar to pointers during creation and destruction, and most similar to a normal variable type during usage.

    There are other minor gotchas with references, but IMO this is the big one.

    0 讨论(0)
  • 2021-01-23 00:07

    You are writing definitions here, with initializations. That means that you're refering to code like this:

    void foo() {
        int i = 0;
        int& r = i;
    }
    

    but not

    class bar {
        int m_i;
        int& m_r;
        bar() : i(0), r(i) { }
    };
    

    The distinction matters. For instance, you can talk of the effects that m_i and m_r have on sizeof(bar) but there's no equivalent sizeof(foo).

    Now, when it comes to using i and r, you can distinguish a few different situations:

    • Reading, i.e. int anotherInt = r;
    • Writing, i.e. r = 5
    • Passing to a function taking an int, i.e. void baz(int); baz(r);
    • Passing to a function taking an int&, i.e. void baz(int&); baz(r);
    • Template argument deduction, i.e. template<typename T> void baz(T); baz(r);
    • As the argument of sizeof, i.e. sizeof(r)

    In these cases, they're identical. But there is one very important distinction:

    std::string s = std::string("hello");
    std::string const& cr = std::string("world");
    

    The reference extends the lifetime of the temporary it's bound to, but the first line makes its a copy.

    0 讨论(0)
提交回复
热议问题