These are exceptionally good questions that you're asking. A firm understanding of these issues is required to understand any language!
Is it actually pushing in the value or is it pushing in a pointer to the already allocated memory? |
It's pushing the value. So the vector will contain a copy of the pushed value. Note that
all the standard containers work this way. They all store values, not pointers. So
std::SomeContainer<SomeType>
always stores
SomeType
values, never pointers to
SomeType.
You can create a container of pointers, but you do that explicitly:
std::SomeContainer<SomeType *>
. It's still storing values, but in this case, the value that its storing is itself a pointer.
can I then change the value in the future via vec.back()=1; or even dereferenceing an iterator and simply changing the dereferenced value? |
Yes, and yes. vec.back() returns a reference to the last item in the vector. When you change the reference, you change the value in the vector. Just be sure you don't make this mistake:
1 2
|
int i = vec.back(); // copies the last item in vec to i, which is a different variable.
i = 5; // assign 5 to i but leaves the last item in vec unchanged.
| |
do i have to say
//member
vector<int> a;
a.push_back(0)
auto it=this->a.begin();
this->a.erase(it);
this->a=&a.begin();
|
You don't have to use this->. Also you don't have to do a = &a.begin(). The vector collection takes care of keeping itself consistent.
One thing you DO need to be aware of when inserting and deleting elements in a container is the effect upon any iterators that point to the container. The documentation for the insert() or erase() method will tell you which iterators may be come invalid. DO NOT rely on empirical evidence like "well I ran it twice and the iterator was still valid so I guess it always will be"). Sometimes the iterator only becomes truly invalid if the collection has to reallocate or otherwise move items around. In that case, your program may work sometimes and break other times. Read the documentation and act accordingly.
[When accessing a class member "var", what is the] difference between this->var or just var |
There is no difference at all, provided that var is not also defined in an enclosing scope.
For example,
1 2 3 4 5 6 7
|
MyClass {
int i;
void f(int i) {
i = 0; // assigns to parameter i;
this->i = 1; // assigns to member variable i.
}
};
| |
Sometimes people use
this->
for clarity. People like to do lots of prefixes and suffixes for clarity, but most are counterproductive in my opinion. Consider a reductio ad absurdum:
1 2 3 4 5 6 7 8 9 10 11
|
// Follow all Code Readability Guidelines!
class T_MyClass { // CRG 18.4.5: all types begin with "T_"
ulli unsigned long long int ulli_m_x; // CRG Volume 8: variable names begin with type prefix (subsections 18.4-18.22: built in types)
// CRG 3.978: member data should be prefixed by m_
// CRG 4-43.E use "long int" and "short int" instead of "long" and "short"
ulli unsigned long long int ulli_m_y; // CRG 8.334-Q: all variables must have their own type declaration.
ulli unsigned long long int ulli_m_y; // Same as above
unsigned long long int f() {
return this->ulli_m_x + this ->ulli_m_y + this->ulli_m_z; // CRG 1.45-D: always prefix members with this->
}
};
| |
which is intended to be more readable than:
1 2 3 4 5 6 7
|
class MyClass {
unsigned long long x,y,z;
unsigned long long f() {
return x+y+z;
}
}
};
| |
Should I get into the habit of something like if I have a class member int var. Initializing a temp pointer and doing one of these. int* temp=&this->var? |
If you're doing it for performance then the answer is no. Let the compiler figure out the optimizations. It's better at it than you are. If you're doing it for readability, then use a reference instead, and make a note in the comments. Here's an actual example:
1 2 3 4 5 6 7 8 9 10 11 12
|
Item &item(sj->items[i]); // short hand
if (item.attempts.empty()) {
continue;
}
rec.xqns[item.aci].push_back(dummyXqn);
XqnInfo &xqn(rec.xqns[item.aci].back()); // short hand
xqn.cc = item.cc;
xqn.ac = item.ac;
xqn.xqn = item.xqn;
for (int j=0; j<item.attempts.size(); ++j) {
xqn.durations.push_back(item.attempts[j].duration);
}
| |
which is a lot more readable (to me anyway) than:
1 2 3 4 5 6 7 8 9 10 11
|
if (sj->items[i].attempts.empty()) {
continue;
}
rec.xqns[sj->items[i].aci].push_back(dummyXqn);
rec.xqns[sj->items[i].aci].back().cc = sj->items[i].cc;
rec.xqns[sj->items[i].aci].back().ac = sj->items[i].ac;
rec.xqns[sj->items[i].aci].back().xqn = sj->items[i].xqn;
for (int j=0; j<sj->items[i].attempts.size(); ++j) {
rec.xqns[sj->items[i].aci].back().durations.push_back(sj->items[i].attempts[j].duration);
}
}
| |
Happy coding!