what does #4 line of C++ code does? - c++

class vector{
public:
vector(int s);
double& operator[](int i);
int size();
private:
double∗ elem;
int sz;
};
Line 4 : double& operator[](int i);
what this line means in C++ programming principles, I get confused where & is used and [](int i) also quite confusing.

It defines the operator [] which returns a reference to the double value of the n-th element within the vector.
In this way you can read and write a specific element.
Suppose you have the following:
vector my_vector(1000);
With the operation double value = my_vector[3] you read the value of the 4th element.
With the operation my_vector[6] = 6.7 you set the value of the 7th element.

It allows you to user the [] parameter on the vector object.
it shows you that it receives an int as a parameter ([i]), and returns a double, so a line like the following will be valid:
double element = vector1[2];
or
vector1[2] = 4; // since the returned value is a reference
where vector1 is an instance of the vector class.

double& operator[](int i);
what this line means in C++
This line declares an operator[] (also known as the "Array subscript operator") implementation, which is commonly used for indexing container types (e.g. std::vector, std::map and others). Imagine the common sequence[0] to access the reference to the first element of a sequence.
where & is used
In C++, the & character appended to a type means "a type that represents a reference to type Foo". So for example int& is a reference to int, and double& is a reference to a double.
Now, why would you return references from an operator[]? The answer is: because you probably want to write code like this...
sequence[0] = 42;
...and for this you need operator[] implementation to return an lvalue. It just so happens that references are lvalues! Why do you need an lvalue? A simplistic answer is "because left-hand side of an assignment must be an lvalue". I found this article helpful when learning about lvalues and rvalues.
and [](int i) also quite confusing.
You parsed this somewhat incorrectly. Look at the declaration this way:
double&
operator[]
(int i)
First part is the return type, second is the name of the function you're implementing, and the third part specifies the parameters your function takes.
Implementations of operator[] should take an integer value (int, unsigned, size_t etc.) as a parameter (disclaimer: not sure, couldn't find a "thou shalt" reference for this). This is why your parameter list is (int).
Further reading: go to http://en.cppreference.com/w/cpp/language/operators and look for "Array subscript operator".

Related

How exactly do I use the functions push_back and pop_back()? I looked them up in the following liks but still don't understand

http://www.cplusplus.com/reference/vector/vector/push_back/ (C++11 Version)
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?;
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
http://www.cplusplus.com/reference/vector/vector/pop_back/
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
If you are a beginner, just read over the additional qualifiers like const, & and &&. The methods in the STL are implemented in a way, that they behave consistent over all overloads:
I will give you a small example here:
std::vector<int> myvector;
myvector.push_back(5);
int five = 5;
myvector.push_back(five);
Now the more in depth part of the answer:
First (const value_type& val). The & character signals, that we take the argument by reference, that means we don't copy the argument, but get a fancy pointer, that will behave like the object itself.
You may not want, that your variable is changed, if you push it back to a vector. To get a promise, by the programmer of the STL, that he will not change your variable while pushing it back to the vector, he can add the const before the type.
The reason it is implemented that way, is that it may prevent an unneeded copy. (First copy the argument onto the stack to call push_back and the second time copy it at the position in the vector. The first copy is unnecessary and saved by the const reference.)
This is all nice and simple, but there are cases, where the compiler is not allowed to take a reference of a value and pass it to a function. In case of temporary values, there is no reference to take, because there is no variable in memory. Take the following line for example.
myvector.push_back(5);
Since the 5 has no address, it can't be passed as a reference. The compiler can not use the first overload of the function. But the programmer also does not want to waste the time for the copy onto the stack. That is why C++11 added new semantic. A so called rvalue for such temporary objects. If you want to write a function to take such an rvalue, you can do so by using type&& rvalue_variable. The value in this case the 5 is moved onto the stack by using the move constructor of the type. For trivial types like int, this will be the same as the copy constructor. For complex types like std::vector there are shortcuts one can take if one is allowed to rip the temporary object apart. In case of the vector, it does not need to copy all the data in the vector to a new location, but can use the pointer of the old vector in the new object.
Now we can look at the example again:
std::vector<int> myvector;
myvector.push_back(5); // push_back(const int&) can't be applied. The compiler chooses push_back(int&&) for us
int five = 5;
myvector.push_back(five); // push_back(const int&) can be applied and is used by the compiler
// The resulting vector after this has the two values [5, 5]
// and we see, that we don't need to care about it.
This should show you how you can use both of them.
push_back():
std::vector<int> vec = { 0, 1, 2 };
vec.push_back(3);
pop_back():
vec.pop_back();
vec.pop_back();
If you need more clarification:
push_back(const T& val) adds its parameter to the end of the vector, effectively increasing the size by 1 iff the vector capacity will be exceeded by its size.
pop_back() doesn't take any parameters and removes the last element of the vector, effectively reducing the size by 1.
Update:
I'm trying to tackle your questions one by one, if there is anything unclear, let me know.
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?;
Prior to C++11, rvalue-references didn't exist. That's why push_back was implemented as vector.push_back(const value_type& val). If you have a compiler that supports C++11 or later, std::vector.push_back() will be overloaded for const lvalue references and rvalue references.
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
You as a programmer do NOT choose how you pass arguments to push_back(), the compiler does it for you automagically, in most cases.
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
value_type is equal to the type of vector that you declared. If a vector is declared with std::string, then it can only hold std::string.
std::vector<std::string> vec;
vec.push_back("str"); // Ok. "str" is allowed.
vec.push_back(12); // Compile-time error. 12 is not allowed.
What is the difference and/or advantages of void push_back (const value_type& val); & void push_back (value_type&& val) and which do you suggest I use?
void push_back(const value_type&) takes an argument, that is then copied into the vector. This means that a new element is initialized as a copy of the passed argument, as defined by an appropriate allocator.
void push_back(value_type&&) takes an argument, that is then moved into the container (this type of expressions are called rvalue expressions).
The usage of either of two depends on the results you want to achieve.
I don't understand how to fill in the arguments (const value_type& val) & (value_type&& val)
In most cases you shouldn't think about which version to use, as compiler will take care of this for you. Second version will be called for any rvalue argument and the first one for the rest. In a rare case when you want to ensure the second overload is called you can use std::move to explicitly convert the argument expression into xvalue (which is a kind of rvalues).
I don't understand the second sentence under the parameter section. (It's a bit too wordy for me to get). I do understand what val is though
The sentence in question is:
Member type value_type is the type of the elements in the container, defined in vector as an alias of its first template parameter (T).
This means that value_type is the same type as the type of vector's elements. E.g., if you have vector<int> then value_type is the same as int and for vector<string> the value_type is string.
Because vector is not an ordinary type, but a template, you must specify a type parameters (which goes into angle brackets <> after vector) when defining a variable. Inside the vector template specification this type parameter T is then aliased with value_type:
typedef T value_type;
It doesn't give an example I can understand real well. Can I get other examples using vectors or some video links that explain the use of the function in practice better?
The main thing you need to remember is that vector behaves like a simple array, but with dynamicly changeable size and some additional information, like its length. push_back is simply a function that adds a new element at the end of this pseudo-array. There is, of course, a lot of subtle details, but they are inconsequential in most of the cases.
The basic usage is like this:
vector<int> v; // v is empty
v.push_back(1); // v now contains one element
vector<float> v2 { 1.0, 2.0 }; // v2 is now a vector with two elements
float f = v2.pop_back(); // v2 now has one element, and f is now equals 2.0
The best way to understand how it works is to try using it yourself.

How do I write different operator[] for LValue and RValue?

I am trying to interface a C library to my C++ project. The library has its own vector type, assume to be VECTOR, and it provides element access:
int vector_set_value(VECTOR* vec, int index, double new_value);
int vector_get_value(VECTOR* vec, int index, double* retrieved_value);
Now it would be good to wrap the get and set operations by operator[] overloading
double& operator[](int index);
const double& operator[](int index) const;
But how do I tell operator[] have different behavior, between vec[index]=3 and double value=vec[3]? For the prior vector_set_value should be called while for the latter vector_get_value should be called.
I would not attempt to wrap one interface into the other.
That being said, if you really want to do this one possible solution is to create a proxy object, and have your operator[] return that proxy object. The proxy object would have conversions into the underlying type const double& for reading, and overloaded operator= for writing. Each one of them would call the appropriate library function.
This will allow for syntax that looks like that of C++ std::vector: MyVector v(...); v[1] = 10.1; double d = v[1]; but it will be problematic. The proxy object cannot replace the real type in all contexts, only in some of them. And even there, the semantics are different, so while it may look like a regular vector, one day you will try to use the proxy in a way it does not support and you will be puzzled at the leaking abstraction

Calling Operator() "function call" to return reference to array element

I think I don't really understand what's behind references, and I'd be glad to learn more about those.
I'm writing a math "vector" Class to do basic linear algeabra for numerical simulation. I was using Eigen before i was convinced not to use external libraries anymore. My problem is pretty straightforward :
I declare vector and sets its 3 components of type Scalar (these are doubles). I can do math with my vectors as I overload operators, but this is beyond the scope of my question.
I want to access the i-th component of my object through the function call operator () as I was used with Eigen : myVector(0) = 0.0 ; or Scalar d = myVector(0)+1.0 ;
According to my understanding of references, this solution should be working :
class mtnVector {
public:
typedef double Scalar;
Scalar data [3];
(setters, math, etc...)
inline Scalar & operator() (const int i) const {
return data[i] ;
}
};
But g++ says that it doesn't like the way I implement it and comfirms I s*** at references :
Vector.h:185: error: invalid initialization of reference of type ?double&? from expression of type ?const double?
What's very strange from my point of view is that if the array containing the data is dynamically set (Scalar * data) (with new operator) at class construction, the code compiles fine. But I don't see the point of having dynamically set data holder.
I don't get neither the need of const to overload the function call operator but I accept it.
Your operator() is declared const. This means that calling the function should never end up modifying the object. That function returns a member of this object by non-const reference, which would allow whoever called operator() to modify the internals of the object. Obviously this would be silly, so the compiler just doesn't allow it. If you're going to return a reference to a member from a const member function, you need to make that reference const:
inline const Scalar& operator() (const int i) const {
return data[i] ;
}
You might want to provide both a const and non-const version of the function, one of which returns a const Scalar& and the other a Scalar& (this is how the standard library containers do it).
It seems strange that you'd want to use operator() for this. Your expression myVector(0) would look more natural as myVector[0], which you can achieve through overloading operator[] instead.
Also, you should ignore whoever convinced you that you shouldn't use external libraries. Eigen, in particular, is a very mature and thoroughly tested library. Unless you really have a good reason, you should be using it.

Clarification on Operators

I've been reading up on class operators and came across the following example:
class Array {
public:
int& operator[] (unsigned i) { if (i > 99) error(); return data[i]; }
private:
int data[100];
};
Does this mean I can replace [ and ] with whatever I want? For example, could I use parentheses?
Also, what is the significance of the ampersand in int& operator[]?
On a slightly less important note, would it be syntactically correct to use int& operator [] instead of int& operator[]?
Does this mean I can replace [ and ] with whatever I want?
Nopes! Not all operators can be overloaded.
For example, could I use parentheses?
You can but you shouldn't.
Also, what is the significance of the ampersand in int& operator[]?
It means you are returning a reference to an int variable.
EDIT: On a slightly less important note, would it be syntactically correct to use int& operator [] instead of int& operator[]?
There is no difference between the two.
What you are doing is defining an Array class that wrapes a simple integer array. By overloading the [] operator you can acces each element of the array as with any other array, the advantage here is that your are checking superior limit to avoid buffer overflow. The ampersand means that you are returning a reference to the array element, it allows you both assigment a value and getting a value. In c++ when you overload the [] operator dont forget both const and non-const versions:
int& operator[] (conts int a) {...}
int operator[] (conts int a) {...} const
You could use parentheses, because there also is an
operator()
and some libraries (eg. boost::blas) do this. BUT: You cannot make up new parenthesis, because there is no operator{} or operator<>
RE your syntax question: Haven't tried, but don't think so, because operator[] is the name of a function, and you shouldn't add whitespace to a function name.
While you can mostly define operators as you like, parens would be a problem. The reason is conflict with the classes constructor! Array(25), what does it mean? I'm not sure if this is allowed (though I'm quite sure someone else will know), but the point is that even if you are allowed you are going to have a problem with doing that.
In general - symbols that serve as operators can be overloaded/redefined You can specify how ==, &, > and [] work for your class. You can't decide the letter 'q' now means some type of comparison. As far as the () issue, im not sure.
The reference mark & is necessary for indexing because you want to potentially do assignment on the address returned, not just got a value. If you permit the lax description, the "majority' of your operators will not require this.
1) NO there is a fixed set of available 'overloadable' operators in C++.
See this table in wikipedia:
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Table
There is an 'Overloadable' Column in each table
2) The int& indicates that you're returning a Reference to the value.
References in C++ are similar to pointers and worth their own discussion, but in the case of the operator here what it allows if for you to use this operator as the left hand operand of an assignment e.g.
x[3] = 0;
This wouldn't work if it just returned an int;

operator[][] C++

I'd like to overload operator[][] to give internal access to a 2D array of char in C++.
Right now I'm only overloading operator[], which goes something like
class Object
{
char ** charMap ;
char* operator[]( int row )
{
return charMap[row] ;
}
} ;
It works ok.. Is it possible to override operator[][] though?
Don’t try to do that – as others have said, overloading operator [] the way you do actually provides the [][] syntax for free. But that’s not a good thing.
On the contrary – it destroys the encapsulation and information hiding of your class by turning an implementation detail – the char* pointer – to the outside. In general, this is not advisable.
A better method would be to implement an operator [,] which takes more than one argument, or indeed an operator [][]. But neither exists in C++.
So the usual way of doing this is to ditch operator [] altogether for more than one dimension. The clean alternative is to use operator () instead because that operator can have more than one argument:
class Object
{
char ** charMap ;
char& operator ()(int row, int column)
{
return charMap[row][column];
}
};
For more information, see the article in the C++ FAQ Lite.
There is no operator [][]: that's two [] operations in a row. You could:
Have Object::operator[] return an object of a second class representing a row, which has its own operator[] method that takes a column number;
Write a get(int row, int column) method and use that instead of operator overloading. I'd recommend this unless your object absolutely has to behave like an array.
There is no operator[][]. Evaluating a[x][y] first calls operator[] on a, and then operator[] again on the result of that.
So the operator[] of your object has to return another object with its own operator[], which then will access the requested value.
As far as I know there is no such thing as operator[][]. What you can do is you could return from your operator[] method something that has overloaded operator[].
Actually you are doing it now, because you return char* which can be indexed using [] again.
There is no [][] operator. What actually happens is that the second [] operates on the variable returned by the first []. Because there is already that functionality, it would create ambiguity were there to exist a [][] operator.
For example: let's say you have a variable x of some type T.
T x = new T();
If we use the [] operator, let's say a variable of other type Q is returned:
Q y = x[0];
And then using the [] operator on a variable of type Q might return a variable of type R:
R z = y[0];
Therefore x[][] returns a variable of t ype R.
Let's say we actually were able to overload [][] for type T such that it returned a type S:
S a = x[0][0];
The compiler would have no way of knowing if it should use the [][] operator on x to return a type S variable, or use the [] operator twice in a row to return a type R variable. This is the ambiguity I mentioned above.
Your best bet if you're stuck on using square brackets is to have operator[] return a variable which also has [] overloaded (or perhaps a variable of the same type, with a flag set), and have that initially returned variable deal with the second [].
But the best solution here (as mentioned already in another answer) is to use a different operator such as ().