I'm a bit confused atm, I don't know when to use const T& or T& or T as a parameter.

Currently I'm doing:

void Resize(std::vector<T> &Vec, const size_t &NewLength)  //Ahh edited the function as a result of Lucaci's answer.
{
    Vec.resize(NewLength);
}


//But thinking of doing:

void Resize(std::vector<T> &Vec, size_t &NewLength)
{
    Vec.resize(NewLength);
}

//And:

void Resize(std::vector<T> &Vec, size_t NewLength)
{
    Vec.resize(NewLength);
}


//The reason I'm thinking like this is because I may have to pad the vector like so:

void Resize(const std::vector<T> Vec, const size_t &NewLength, const T& Padding)
{
    Vec.resize(NewLength, Padding);
}

Now my question is: Which is the best to use? If I use const T&, will it create temporaries every single time? Inother words, will it create a copy of the padding every single time the function is called? Will it create a copy of the padding only once for the resize or will it do it NewLength amount of times or not at all?

Basically I want to know if const T& works the same as T&. I don't want to copy anything as I need the speed. Also what is the difference between const T* vs const T&?

Recommended Answers

All 2 Replies

I think you can't pass a vector as const vector<string> &vect and still resize it, because the const argument insures that the element passed will not be change, whereas resizeing will change it, so it will yield a compiler error.
Passing the vector as vector<string> vect will pass a copy of that vector, and the original vector will not be modiffied.
Passing the vector as vector<string> &vect will pass the vector by reference, and all modifications done on it, inside that function, will be seen outside of it.

Which is the best to use?

It really depends on the case. Explanation below.

If I use const T&, will it create temporaries every single time?

No. The whole point of it is that it won't create any temporaries. However, it will cause indirection, meaning that it is like a pointer (under-the-hood) and thus, everytime you access the value of the referee, there is an implicit dereferencing happening (fetching the value at the underlying pointer address. This is the core of the issue, with a reference parameter, you eliminate the overhead of the copying (replacing it with the often cheaper operation of taking a reference (address) and copying that address (underlying pointer)), but then you suffer the overhead of the indirection every time you access the referee's value.

So, we can first take care of the case for T&, because that's easy. If you need to modify the call-site object that is given as a parameter, then you must use T& (unless you go with T*, however, that is usually not recommended).

If you need a fresh copy of the object within your function (e.g., to do some temporary modifications to it), then you should use T (pass-by-value). This is because if you are going to make an internal copy of the object (internal to the function-body), you might as well do it as it is being passed into the function because it is going to help the compiler avoid unnecessary copies from the call-site.

If you don't need an internal copy and don't need to modify it, i.e., if a read-only object is all you need within the function, then you have two choices, either const T& or T. Here's how you decide. Considering the trade-off I mentioned above (object-copies versus pointer-and-indirection) it becomes quite clear which to choose. If the object is large and/or its copying is expensive, then you stand to gain a lot by avoiding the copies and losing relatively little with the pointer-indirection business. However, if the object is small and cheap to copy (more or less comparable to copying a couple of pointers or int values), then you would probably be better off passing by value to avoid unnecessary indirection, since the copying around of the pointer (within the reference) will be almost the same as copying the object itself. In my experience, if the object is a simple POD-type (contains only data members of more-or-less primitive types, with very simple constructors) and that its size is at most 3-4 times the native word size (e.g., size of int), then it is better to pass-by-value. Otherwise, use const T&. Of course, if you don't know the actual type (e.g., in a function template), then just use const T& to be safe.

Also what is the difference between const T* vs const T&?

The first is a pointer to a const object of type T, the second is a reference to a const object of type T. So, what they have in common is this:

  • They both refer to another object (pointee or referee); and,
  • They both do not allow you to modify that pointee or referee.

What makes them different is this:

  • Pointer syntax is explicit about the referencing / dereferencing, which means that you'll have to use the address-of operator & and the dereferencing operators * and -> when you access the pointee. By contrast, reference syntax is implicit (under-the-hood), which is nicer, cleaner, and safer.
  • References are inherently difficult to copy, mostly because they cannot be re-seated, meaning that a reference is initialized (upon construction) to refer to a given object and that can never be changed afterwards. This means that if you are given a reference to an object as a parameter to a function, it will be difficult (well, not really) to keep that reference beyond the life-time of the function. To do so, of course, you can use the address-of operator & to get a pointer to the referee object, but that is an explicit syntax that is unlikely to be done by mistake, as opposed to pointers that can easily get copied by mistake and then you end up having a pointer to an object that no longer exists (this is usually called a dangling pointer or dangling reference). References make it easier not to make such mistakes.
  • A const-reference can bind to a temporary object, something pointers cannot do. If you want to pass a temporary object (called an "rvalue" in C++ standard terminology) which could be a literal expression (like 3, 0.5, or "Hello world") or an object created on-the-spot (without a name, like std::string("Hello world")), then, the C++ language allows that temporary to be referred to by a const-reference, even though the address (in memory) of that temporary is only valid for the time of the function execution. This cannot be done with pointers, because you cannot take the address of an rvalue (temporary variable).
  • Finally, in C++ coding practices, there is a general understanding that if an object is passed by reference (const or not) to a function, then that object is only required to exist until the function returns. Similarly, if an object is passed by reference to an object constructor, and it is clearly stated (in docs) that this class wraps a reference to that object, then it is understood that the referee object needs to exist for as long as the reference-wrapper object exists. With pointers, things are a bit more ambiguous, and it can make some programmers uncomfortable and annoyed (e.g., I'm very comfortable using functions that have reference-parameters, but if an unknown function (from a library) has a pointer-parameter, I always have to check the docs to know what this pointer is going to be used for, and that's annoying, especially when you realized it could just as well have been a reference-parameter instead).

Basically, a pointer is an address-value, which could point somewhere (to an object), no-where (null), or to anywhere (freed memory, deleted object, outside the address-space (causing a segmentation-fault)). A reference is quite literally an alias for a specific object, i.e., it's another name for the same object, and this is how they are intended to be used and this is how they are mostly used in practice.

Raw-pointers are also ambiguous about ownership, another reason to avoid them. Reading my tutorial on ownership might help.

commented: I chose my function parameters based on this answer :) +5
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.