开发者

Whats the significance of return by reference?

In C++,

function() = 10;

works if the function returns a variable by reference.

What are the use cases of i开发者_Python百科t?


The commonest case is to implement things like operator[].

struct A {
    int data[10];
    int & operator[]( int i ) {
         return data[i];
    }
};

Another is to return a big object from a class via an accesor function:

struct b {
    SomeBigThing big;
    const SomeBigThing & MyBig() const {
         return big;
    }
};

in order to avoid the copying overhead.


Consider the following code, MyFunction returns a pointer to an int, and you set a value to the int.

int  *i;
i = MyFunction();
*i = 10;

Now shorten that to

*(MyFunction()) = 10;

It does exactly the same thing as the first code block.

You can look at a reference as just a pointer that's always dereferenced. So if my function returned a reference - not a pointer - to an int the frist code block would become

int  &i;
i = MyFunction();
i = 10;

and the second would become

MyFunction() = 10;

This is what i was looking for


Getters/setters for instance

class C
{
    int some_param_;
public:
    int& param() { return some_param_; }
    int const& param() const { return some_param_; }
};

but here you should go with some_param being a public int. Containers provide functions that return by reference, eg. vector<T>::operator[] so that you can write v[k] = x.


A very normal use case is when you write an array like class. Here you want to overload the operator [] so as you can do a[0] = 10; In that case you would want the signature to be like int& operator[](int index);


In case you have a class that contains another structure, it can be useful to directly modify the contained structure:

struct S
{
    int value;
};

class C
{
    public:

        S& ref() { return m_s; }

    private:

        S m_s;
};

Allows you to write something like:

void foo()
{
    C c;

    // Now you can do that:

    c.ref().value = 1;
}

Note: in this example it might be more straightforward to directly make m_s public rather than returning a reference.


SO screwed up my answer

You don't even need to return a reference:

struct C { };

C f() {
  return C();
}

int main() {
  C a;
  f() = a;  // compiles fine
}

Because this behavior is quite surprising, you should normally return a const value or a const reference unless the user has a sensible intent to modify the result.


It can be usefull when implementing accessors

class Matrix
{
   public:
      //I skip constructor, destructor etc

      int & operator ()(int row, int col)
      {
         return m_arr[row + col * size];
      }

   private:
      int size;
      int * m_arr;
}

Matrix m(10);
m(1,0) = 10;  //assign a value to row 1, col 0


Another classic case:

class Foo {
  Foo();
public:
  static Foo& getSingleton();
};


std::vector has operator[] which would not allow vec[n] = m otherwise.


You can also achieve method chaining (if you so desire) using return by reference.

class A
{
public:
    A& method1()
    {
        //do something
        return *this;   //return ref to the current object
    }
    A& method2(int i);
    A& method3(float f);  //other bodies omitted for brevity
};

int main()
{
    A aObj;
    aObj.method1().method2(5).method3(0.75);

    //or use it like this, if you prefer
    aObj.method1()
        .method2(5)
        .method3(0.75);
}


The named parameter idiom is a another use case. Consider

class Foo
{
public:
    Foo(
        int lions,
        float tigers,
        double bears,
        std::string zookeeper
    );
};

users of this class need to remember the position of each parameter

Foo foo( 1, 2.0, 5, "Fred" );

which can be non-obvious without looking at the header. Compared to a creator class like so

class CreateFoo
{
friend class Foo;
public:
    CreateFoo();

    CreateFoo& lions(int lions) {
        _lions = lions;
         return *this;
    }

    CreateFoo& tigers(float tigers) {
        _tigers = tigers;
        return *this;
    }

    CreateFoo& bears(double bears) {
        _bears = bears;
        return *this;
    }

    CreateFoo& zookeeper(const std::string& zookeeper) {
        _zookeeper = zookeeper;
        return *this;
    }

private:
    int _lions;
    float _tigers;
    double _bears;
    std::string _zookeeper;
};

which can then be used by clients like so

Foo foo = CreateFoo().
    lions(1).
    tigers(2.0).
    zookeeper("Fred").
    bears(5)
    ;

assuming Foo has a constructor taking a const CreateFoo&.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜