STL pass by reference

Feb 3, 2012 at 8:00pm
I have a buffer (sound) that I want to pass around for other objects (radio stations) to contribute to.

I'm using the queue stl container. Can you pass such a container by reference?

I'm in the planning phase, so I haven't been able to test much yet although this does compile.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <queue>
#include <vector>
#include <string>
using namespace std;

class cSoundIF
{
  string _message;
  float _freq;
public:
  cSoundIF(string message, float freq) : _message(message), _freq(freq) {}
};

class cStations
{
public:
  cStations() {}
  void step(queue<cSoundIF> &lSoundBuf) //passing by reference here
  {
    lSoundBuf.push(cSoundIF("Hello",107.1f)); // Hard coded for this post
  }
};

void PlaySounds(queue<cSoundIF> &lSoundBuf) //passing by reference here
{
  while (!lSoundBuf.empty())
  {
    //Playing the sounds, then:
    lSoundBuf.pop();
  }
}

int main()
{
  vector<cStations> vStation;
  while(true)
  {
    queue<cSoundIF> qSoundBuf;

    if (rand()%250) vStation.push_back(cStations()); //Add a station at random

    for (vector<cStations>::iterator it = vStation.begin(); it < vStation.end(); it++)
      it->step(qSoundBuf); //Add messages for each station, passing by reference

    if (rand()%250 && !vStation.empty()) vStation.pop_back(); //Delete a station

    PlaySounds(qSoundBuf); //Play the messages,  passing by reference
  }

  return 0;
}
Last edited on Feb 3, 2012 at 8:31pm
Feb 3, 2012 at 9:22pm
Yes you can pass by reference and is my prefered method of passing an object.
Feb 3, 2012 at 9:39pm
Cool,

How about if I want to pass it into the windows "CreateThread()" function? To do this, I need to send a void pointer. The recipient wouldn't know the size of the object so I'm not sure if the resulting STL container in the function would understand how to construct itself.
Last edited on Feb 3, 2012 at 9:44pm
Feb 3, 2012 at 9:47pm
You can pass anything by const reference(const&) and only non const lvalue(not a temporary object) by reference. It doesn't depend on the type.
In fact, you should pass anything except buitlin types(like int, float, ...) and very small types like functors by constant refrerence if the function doesn't modify the parameters and by reference otherwise if you want decent performance.
Bultin and small types have to be passed by value to avoid useless dereference. And for builtin types like int, the fact of passing them by reference instead of by value prevent them to be stored in register which decrease performance.
In your code for example, you should change cSoundIF(string message, float freq) at line 11 by cSoundIF(string const& message, float freq).
Feb 3, 2012 at 9:51pm
You can pass objects by reference, Stewbond, and that is, in fact, the preferred method of professional programmers. I would change your class, for example, to:

1
2
3
4
5
6
7
8
9
class cStations
{
public:
    cStations() {}
    virtual void step(const queue<cSoundIF>& lSoundBuf)
    {
        lSoundBuf.push(cSoundIF("Hello",107.1f));
    }
};


If you're passing to an external function, though, all you have to worry about is putting the variable in there. You can't specify how the function treats your variable, you can only provide your variable to it. You basically have to trust the library writer to know how to use your variable correctly.

Feb 3, 2012 at 9:59pm
ciphermagi there sould not be a const at line 5, or else the push method can't work.
Feb 3, 2012 at 10:13pm
I thought virtual was just for inheritance purposes. What role would it play here?

Thanks for the advice guys. I'm reforming my code. I can't wait until it is assembled enough to try it out.
Feb 3, 2012 at 10:13pm
You don't have to pass by const&, but it is preferred. If you want to be able to mutate the originally passed value (not a copy), then pass by ref. If you want to mutate a copy, then pass by value. All other times, pass by const&.

And let's be real. You can pass by const& and remove the const by const_cast.
Feb 3, 2012 at 10:18pm
That a good explanation regarding the const&. I always wondered why people used/recommended it.
Feb 3, 2012 at 10:30pm
Stewbond: As a matter of principle, anytime you're making a class, you should make your non-static functions virtual. This makes it so that any person that uses your code and creates a sub-class of your class (including yourself!) can actually force the function's actions to change to be different than that of the superclass. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Poly
{
protected:
    int mHeight, mWidth;
    double mArea;
    virtual double setArea(const int& mHeight, const int mWidth); // Superclass setArea
public:
    virtual void setHeight(const int& inHeight);
    virtual int getHeight() const;
    virtual void setWidth(const int& inWidth);
    virtual int getWidth() const;
    virtual double getArea() const;
};

double Poly::setArea(const int& mHeight, const int& mWidth)
{
    return mHeight * mWidth; // Superclass returns height * width for area
}

// Other functions omitted for brevity

class Triangle : public Poly
{
protected:
    virtual double setArea(const int& mHeight, const int& mWidth); // Triangle overrides superclass
};

double Triangle::setArea(const int& mHeight, const int& mWidth)
{
    return (mHeight * mWidth) / 2; // Triangle setArea returns a proper triangle area calculation
}


Without having set it as virtual, the setArea from the triangle will still be used, but it will not override the Poly version, it merely hides it. This means that the Poly version is still accessible through some methods when you try to call triangle's setArea function. This is not generally considered to be desirable behaviour.

Edit: Typos
Last edited on Feb 3, 2012 at 10:41pm
Feb 3, 2012 at 10:44pm
As a matter of principle, anytime you're making a class, you should make your non-static functions virtual.

eeeh. I don't agree with this. Why do you think most of the member functions in the standard library is non-virtual? Most classes are not meant to be inherited from so why use virtual? It just adds unnecessary overhead if you never going to override the function. If you are making a function virtual you probably want to make the destructor virtual as well.
Feb 3, 2012 at 10:47pm
Yes, the destructor should also be virtual. The only time you would not make something virtual is if you are explicitly attempting to prevent it from being overridden, such as is the case in the standard library.

Your own classes, unless you never ever intend to use them ever again, should be made virtual, so that you don't have to go back and modify your code repeatedly in order to 'write once; use always'
Feb 4, 2012 at 6:32pm
ciphermagi, C++ is not Java. If the default behavior is to be not virtual there is a good reason: a virtual call is much more costly than a non-virtual one because of the dynamic dispatch and if one class has at least one virtual method it add a vptr to the class. Generally you choose C++ over higer level languages for performance.

And let's be real. You can pass by const& and remove the const by const_cast

Are you serious? Why would you do such a stupid thing?
Topic archived. No new replies allowed.