Arrow operator and vectors - c++

I've been attempting to reassign a particular vector element to a new value and received a error from the compiler, and I'm not sure I understand it. So I believed that you could reassign a single vector element in the same way you could reassign an array's element.
std::vector<int> myVector[10];
myVector[5] = 6;
Or you could alternatively use the built in '.at' to access the vector with bounds checking. When I was writing some trivial code just to understand some concepts better I ran across a peculiar situation.
int main()
{
std::vector<int> test[10];
test[3] = 5;
if (test[3] != 6)
{
std::cout << "It works!" << std::endl;
}
return 0;
}
Now this piece of code flags an error saying that the assignment operator '=' and the logical operator '!=' doesn't match based on these operands. Now if I use the arrow operator '->' the code works just fine. Which is good, but I thought, perhaps mistakenly, that the arrow operator was used when dereferencing a pointer-to-object. I attempted to google these results, but perhaps due to the very rudimentary nature of it, I couldn't find much on the topic. Although, I would like to mention on a few sites with "c++ tutorials" I did see that they used the assignment operator without dereferencing the vector. Now this happens in both Visual Studios 2017 as well as the most recent version of Code::Blocks. Was I wrong? Do you actually need to utilize the arrow operator? Or am I missing something even more basic?

You created an array of 10 vectors, not a vector of 10 elements. A vector is is ultimately a class type, so you need to initialize it via a constructor:
std::vector<int> test(10);
The way you did it originally, meant you tried to assign the value 5 for the vector at index 3. Vectors don't support being assigned numbers, so that's what the error is about.

You're declaring an array of vectors rather than one vector of some initial length. Use the following instead of your declaration:
std::vector<int> myVector(10);

Related

Binary '=': no operator found which takes a left-hand operand of type 'const Thing'

I have read duplicates but really didn't help me.
I am trying to reach next behaviour.
Having a vector composed by pairs {Thing, set < Thing >}
I want a final result of{Thing, newSetOfThing < Thing >}
where that 'newSetOfThing' is the difference applied with every other
sets in the vector but himself. Difference means to have all values but contained on other sets. I am using std::set_difference.
Giving a closer example with numbers.
vector = {[1, {3,4,5,7}], [2,{1,3,9}], [3, {1,2,12}]};
==>
vectorResult = {[1, {4,5,7}], [2, {9}], [3, {2,12} }
Then my code looks like this:
class Thing {
public:
Thing () {
};
~Thing () {};
int position; //id
bool operator<(const Thing &Other) const;
};
bool Thing::operator<(const Thing &Thing) const
{
return(Other.position<position);
}
//The original vector
vector<pair<Thing, set<Thing>>> pairWithSet;
// I fill vector here [...]
// variable I define to store partial results
set<Thing> differenceResult;
// Vector I want to fill for results
vector<pair<Thing, set<Thing>>> newPairWithSet;
// Operation
for (pair<Thing, set<Thing>> currentPair : pairWithSet){
Thing currentThing= currentPair.first;
differenceResult = currentPair.second;
for (int i=0; i<pairWithSet.size();i++) {
if (pairWithSet[i].first.position != currentThing.position) {
set_difference(differenceResult.begin(),
differenceResult.end(),
pairWithSet[i].second.begin(),
pairWithSet[i].second.end(),
differenceResult.begin());
}
newPairWithSet.push_back(pair<Thing, set<Thing>>(currentThing, differenceResult));
}
I explain my objective to you have a point from where to go but at the end I think problem is more related of how wrong I am using set_difference operation and that I cant directly assign 'Thing'. So set_difference has not a way to check if they are the same. Because error is
binary '=': no operator found which takes a left-hand operand of type
'const Thing' (or there is no acceptable conversion
I say because maybe there are other errors to reach behaviour since I can't still debug until I solve problem with operator.
My question is if I need to declare that '=' operation and how. Or If I miss something and I need to perform by another way.
I can ensure problem is when I use set_difference, If I comment this part compiler does the task:
set_difference(differenceResult.begin(),
differenceResult.end(),
pairWithSet[i].second.begin(),
pairWithSet[i].second.end(),
differenceResult.begin());
And I think is because at the end it is trying to perform an assignment to a const (because std::pair declaration?), as it says error (then obviously compiler does not know how to operate). So I have not clear how to perform it recursive set_difference.
set_difference writes results into place pointed by its 5-th argument. You are passing differenceResult.begin() what is wrong, because begin for set always returns const iterator. You cannot do write operation where a destination is object pointed by const iterator.
If you want to store Thing objects into set as result of set_difference algorithm, you can use std::inserter:
set<Thing> res; // CREATE EMPTY SET
set_difference(differenceResult.begin(),
differenceResult.end(),
pairWithSet[i].second.begin(),
pairWithSet[i].second.end(),
std::inserter(res,res.begin())); // CREATE INSERT_ITERATOR WHICH INSERTS THINGS INTO RES
then you can copy res into newPairWithSet.

Copying vector elements to a vector pair

In my C++ code,
vector <string> strVector = GetStringVector();
vector <int> intVector = GetIntVector();
So I combined these two vectors into a single one,
void combineVectors(vector<string>& strVector, vector <int>& intVector, vector < pair <string, int>>& pairVector)
{
for (int i = 0; i < strVector.size() || i < intVector.size(); ++i )
{
pairVector.push_back(pair<string, int> (strVector.at(i), intVector.at(i)));
}
}
Now this function is called like this,
vector <string> strVector = GetStringVector();
vector <int> intVector = GetIntVector();
vector < pair <string, int>> pairVector
combineVectors(strVector, intVector, pairVector);
//rest of the implementation
The combineVectors function uses a loop to add the elements of other 2 vectors to the vector pair. I doubt this is a efficient way as this function gets called hundrands of times passing different data. This might cause a performance issue because everytime it goes through the loop.
My goal is to copy both the vectors in "one go" to the vector pair. i.e., without using a loop. Am not sure whether that's even possible.
Is there a better way of achieving this without compromising the performance?
You have clarified that the arrays will always be of equal size. That's a prerequisite condition.
So, your situation is as follows. You have vector A over here, and vector B over there. You have no guarantees whether the actual memory that vector A uses and the actual memory that vector B uses are next to each other. They could be anywhere.
Now you're combining the two vectors into a third vector, C. Again, no guarantees where vector C's memory is.
So, you have really very little to work with, in terms of optimizations. You have no additional guarantees whatsoever. This is pretty much fundamental: you have two chunks of bytes, and those two chunks need to be copied somewhere else. That's it. That's what has to be done, that's what it all comes down to, and there is no other way to get it done, other than doing exactly that.
But there is one thing that can be done to make things a little bit faster. A vector will typically allocate memory for its values in incremental steps, reserving some extra space, initially, and as values get added to the vector, one by one, and eventually reach the vector's reserved size, the vector has to now grab a new larger block of memory, copy everything in the vector to the larger memory block, then delete the older block, and only then add the next value to the vector. Then the cycle begins again.
But you know, in advance, how many values you are about to add to the vector, so you simply instruct the vector to reserve() enough size in advance, so it doesn't have to repeatedly grow itself, as you add values to it. Before your existing for loop, simply:
pairVector.reserve(pairVector.size()+strVector.size());
Now, the for loop will proceed and insert new values into pairVector which is guaranteed to have enough space.
A couple of other things are possible. Since you have stated that both vectors will always have the same size, you only need to check the size of one of them:
for (int i = 0; i < strVector.size(); ++i )
Next step: at() performs bounds checking. This loop ensures that i will never be out of bounds, so at()'s bound checking is also some overhead you can get rid of safely:
pairVector.push_back(pair<string, int> (strVector[i], intVector[i]));
Next: with a modern C++ compiler, the compiler should be able to optimize away, automatically, several redundant temporaries, and temporary copies here. It's possible you may need to help the compiler, a little bit, and use emplace_back() instead of push_back() (assuming C++11, or later):
pairVector.emplace_back(strVector[i], intVector[i]);
Going back to the loop condition, strVector.size() gets evaluated on each iteration of the loop. It's very likely that a modern C++ compiler will optimize it away, but just in case you can also help your compiler check the vector's size() only once:
int i=strVector.size();
for (int i = 0; i < n; ++i )
This is really a stretch, but it might eke out a few extra quantums of execution time. And that pretty much all obvious optimizations here. Realistically, the most to be gained here is by using reserve(). The other optimizations might help things a little bit more, but it all boils down to moving a certain number of bytes from one area in memory to another area. There aren't really special ways of doing that, that's faster than other ways.
We can use std:generate() to achieve this:
#include <bits/stdc++.h>
using namespace std;
vector <string> strVector{ "hello", "world" };
vector <int> intVector{ 2, 3 };
pair<string, int> f()
{
static int i = -1;
++i;
return make_pair(strVector[i], intVector[i]);
}
int main() {
int min_Size = min(strVector.size(), intVector.size());
vector< pair<string,int> > pairVector(min_Size);
generate(pairVector.begin(), pairVector.end(), f);
for( int i = 0 ; i < 2 ; i++ )
cout << pairVector[i].first <<" " << pairVector[i].second << endl;
}
I'll try and summarize what you want with some possible answers depending on your situation. You say you want a new vector that is essentially a zipped version of two other vectors which contain two heterogeneous types. Where you can access the two types as some sort of pair?
If you want to make this more efficient, you need to think about what you are using the new vector for? I can see three scenarios with what you are doing.
The new vector is a copy of your data so you can do stuff with it without affecting the original vectors. (ei you still need the original two vectors)
The new vector is now the storage mechanism for your data. (ei you
no longer need the original two vectors)
You are simply coupling the vectors together to make use and representation easier. (ei where they are stored doesn't actually matter)
1) Not much you can do aside from copying the data into your new vector. Explained more in Sam Varshavchik's answer.
3) You do something like Shakil's answer or here or some type of customized iterator.
2) Here you make some optimisations here where you do zero coping of the data with the use of a wrapper class. Note: A wrapper class works if you don't need to use the actual std::vector < std::pair > class. You can make a class where you move the data into it and create access operators for it. If you can do this, it also allows you to decompose the wrapper back into the original two vectors without copying. Something like this might suffice.
class StringIntContainer {
public:
StringIntContaint(std::vector<std::string>& _string_vec, std::vector<int>& _int_vec)
: string_vec_(std::move(_string_vec)), int_vec_(std::move(_int_vec))
{
assert(string_vec_.size() == int_vec_.size());
}
std::pair<std::string, int> operator[] (std::size_t _i) const
{
return std::make_pair(string_vec_[_i], int_vec_[_i]);
}
/* You may want methods that return reference to data so you can edit it*/
std::pair<std::vector<std::string>, std::vector<int>> Decompose()
{
return std::make_pair(std::move(string_vec_), std::move(int_vec_[_i])));
}
private:
std::vector<std::string> _string_vec_;
std::vector<int> int_vec_;
};

Defining a C array where every element is the same memory location

In C (or C++), is it possible to create an array a (or something that "looks like" an array), such that a[0], a[1], etc., all point to the same memory location? So if you do
a[0] = 0.0f;
a[1] += 1.0f;
then a[0] will be equal to 1.0f, because it's the same memory location as a[1].
I do have a reason for wanting to do this. It probably isn't a good reason. Therefore, please treat this question as if it were asked purely out of curiosity.
I should have said: I want to do this without overloading the [] operator. The reason for this has to do with avoiding a dynamic dispatch. (I already told you my reason for wanting to do this is probably not a good one. There's no need to tell me I shouldn't want to do it. I already know this.)
I suppose a class like this is what you need
template <typename T>
struct strange_array
{
T & operator [] (int) { return value; }
private:
T value;
};
You can always define an array of pointers which points towards the same variable :
typedef int* special;
int i = 0;
unsigned int var = 0xdeadbeef;
special arr[5];
for (i=0; i<5; i++)
arr[i] = &var;
*(arr[0]) = 0;
*(arr[3]) += 3;
printf("%d\n", *(arr[2]));
// -> 3
In C, I don't think so.
The expression a[i] simply means *(a + i), so it's hard to avoid the addition due to the indexing.
You might be able to glue something together by making a (the array name) a macro, but I'm not sure how: you wouldn't have access to the index in order to compensate for it.
Without overloading operator[]?
No, it's not possible.
Fortunately.
From all that conversation here, I now understand the problem as follows:
You want to have the syntax of an array, e.g.
a[n] // only lookup
a[n]++ // lookup and write
but you want to have the semantics changed to all of those map to the same element, like
a[0]
a[0]++
The C++ way to achieve this is IMHO to overload the index access operator [].
But, you don't want it for performance reasons.
I join the opinon of user Lightness Races in Orbit that you can not do this within C++.
As you don't provide more information about the use case it is hard to come up with a solution.
Best I can imagine is that you have lots of written code which uses array semantics which you can not change.
What is left (wanting to keep performance) are code transformation techniques (CPP, sed, ..), generating a source code from the given source code with the desired behaviour, e.g. by forcing all index values to 0.

accessing multi-dimensional array element c++

I am trying to work with a multi-dimensional array in MSVS2010 console application, and I need to access members of a 2D array. I instantiate the array as
Thing::Thing(int _n){
// size of the array
this.m = _n;
thing = new int*[m];
for(int ii = 0; ii < m; ii++){
thing[ii] = new int[m];
}
}
this is working fine. though when I go to do a operator=, or operator== that both use the similar structure of:
Thing& Thing::operator=(const Thing & _thing){
for(int ii = 0; ii < m; ii++){
for(int jj = 0; jj < m; jj++){
thing[ii][jj] = _thing[ii][jj]; //error thrown on this line
}
}
return *this;
}
this throws 2 errors
binary "[": 'const Thing' does not define this operator or a conversion to a type acceptable to the predefined operator
IntelliSense: no operator"[]" matches these operands
this doesn't make sense as it is an array of type int, and the "[]" operators have not been altered not to mention that error highlighting only puts it under:
_thing[ii][jj];
I can kinda live without the assignment operator, but I need the comparison operator to have functionality.
You should do: thing[ii][jj] = _thing.thing[ii][jj]; in your assignment loop. And you should also check if the array sizes for both (this and _thing) are the same: it may give a crash otherwise.
You get an error because you are trying to use operator[] (indexing operator) on an object class Thing, not on its internal array. If you want to use the Thing class like an array you should define an indexing operator for it e.g.:
int* Thing::operator[](int idx)
{
return thing[idx];
}
I think you've got your "thing"-s confused. Since:
Thing& Thing::operator=(const Thing & _thing)
you probably want to have:
thing[ii][jj] = _thing.thing[ii][jj];
_thing is the Thing object
_thing.thing is the multidimensional array
Thing is the class, thing is the member, thing the parameter... and you forgot that if you want to access the member in the operator= call then you should use _thing.thing.
Your naming choice is quite bad, so bad that it even confused yourself while you were writing the code (and if it was easy for you to make a mistake now try to imagine how much easier would be for someone else to get confused by this code or even for you in a few months from now).
What about calling for example the class Array instead, the member data and the parameter other? I also would suggest avoiding having leading underscores in names, they are ugly and dangerous at the same time (do you know all the C++ rules about where you can put underscores in names and how many of them you are allowed to use?).
When designing a class or a function you have many things to consider and the class name or the function name is important but is one of the many factors. But for a data member or a variable you only have to choose the type and the name and both of them are most important choices.
So please take the habit of thinking carefully to names, especially of variables. The relative importance is tremendous for them. Variables and data members are just names... the name is actually the only reason for which in programming we like to use variables (the computer instead only uses numeric addresses and is perfectly happy with them).
About the class design you probably would also like defining operator[](int)...
int *operator[](int index) { return data[index]; }
By doing this you will be able to write code like
Array a(m);
a[0][0] = 42;
without the need to explicitly refer to data (and, by the way, this addition would also make your original code working... but still fix the names!!).

C++ vector, return vs. parameter [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
how to “return an object” in C++
I am wondering if there is a difference between the three following approaches:
void FillVector_1(vector<int>& v) {
v.push_back(1); // lots of push_backs!
}
vector<int> FillVector_2() {
vector<int> v;
v.push_back(1); // lots of push_backs!
return v;
}
vector<int> FillVector_3() {
int tab[SZ] = { 1, 2, 3, /*...*/ };
return vector<int>(tab, tab + SZ);
}
The biggest difference is that the first way appends to existing contents, whereas the other two fill an empty vector. :)
I think the keyword you are looking for is return value optimization, which should be rather common (with G++ you'll have to turn it off specifically to prevent it from being applied). That is, if the usage is like:
vector<int> vec = fill_vector();
then there might quite easily be no copies made (and the function is just easier to use).
If you are working with an existing vector
vector<int> vec;
while (something)
{
vec = fill_vector();
//do things
}
then using an out parameter would avoid creation of vectors in a loop and copying data around.
The idiomatic C++ approach would be to abstract over the container type by using an output iterator:
template<typename OutputIterator>
void FillContainer(OutputIterator it) {
*it++ = 1;
...
}
Then it can be used with vector as:
std::vector<int> v;
FillContainer(std::back_inserter(v));
The performance (and other advantages, such as being able to fill a non-empty container) are the same as for your option #1. Another good thing is that this can be used to output in a streaming mode, where results are immediately processed and discarded without being stored, if the appropriate kind of iterator is used (e.g. ostream_iterator).
One would assume parameter is best, but in practice it often is not. This depends on compiler. Some compilers (I think actually most recent compilers) will apply Return Value Optimization - Visual Studio 2005 and later should do it in both cases you have provided (see Named Return Value Optimization in Visual C++ 2005).
The best way to know for sure is to check the disassembly produced.
Adding a fourth variant into the mix:
void FillVector_4(vector<int>& v) {
static const int tab[SZ] = {1,2,3, ... };
v.assign(tab,tab+SZ);
}
If you're thinking about performance version 2 and version 3 may make the compiler create a vector<int> copy for the return value. That is, if the compiler isn't able to do NRVO (named return value optimization). Also, consecutive push_backs without a reserve probably leads to a couple of reallocations since the vector needs to grow. Whether this matters at all depends on your problem you're trying to solve.
You'll be pleased to know that C++0x will make returning a locally created vector very efficient. I also recommend reading David Abrahams article series about efficient value types including passing/returning.
The first definitely does not copy the vector.
The cost of copying the vector could be linear in the number of elements in the vector.
The first introduces no risk of linear behavior on any platform or compiler, and no costs of profiling and refactoring.
At a glance, the first two probably have more resizing of the vector going on, whereas the 3rd one probably does not need to resize the vector as it runs. This can be mitigated by resizing it yourself before the pushbacks.