In C++, when is destructor called automatically for local vector? - c++

For example, say I have the following code:
vector<vector<int>> big;
for (int i=0;i<3;++i){
vector<int> small;
small.push_back(3*i+1);
small.push_back(3*i+2);
small.push_back(3*i+3);
big.push_back(small);
}
for (vector<int> s:big){
for (int a:s){cout<<a<<" ";}
cout<<endl;
}
The cout gives result that big contains the value for vector small in each for loop, I am confused because I thought the vector small will be destructed automatically in each for loop.
Why does the big still have access to the correct value?
Thanks!

When you execute:
big.push_back(small);
a copy of small is added to big. You can verify that they are two different objects by executing the following:
std::cout << (void*)&big.back() << std::endl; // big.back() returns a reference to the copy.
std::cout << (void*)&small << std::endl;
You can also verify that they hold the data of the vectors independently. You can print the pointers that hold the data.
std::cout << (void*)big.back().data() << std::endl;
std::cout << (void*)small.data() << std::endl;

That is because you used big.push_back(small); which made a copy of small vector and when small vector was destroyed at the end of the loop the copy was not effected

std::vector<T>::push_back() is copy-based. It creates a copy of the argument, which in this case is small, and stores it in big.
So you're NOT seeing the elements from small, but from big actually.

Related

Incorrect values for overloading multiplication by scalar for a simple Polynomial class in C++

Simplifying: I am trying to write a simple Polynomial class and I get incorrect values when I try to overload the multiplication operator:
#include <iostream>
class Polynomial {
public:
unsigned int degree;
int *coefficients;
Polynomial(unsigned int deg, int* arr) {
degree = deg;
coefficients = arr;
}
~Polynomial() {}
int& operator[](int index) const {
return coefficients[index];
}
};
std::ostream& operator<<(std::ostream &os, const Polynomial& P){
for (unsigned int i=0; i < P.degree; i++) os << P[i] << ",";
os << P.coefficients[P.degree];
return os;
}
Polynomial operator*(const Polynomial &P, const int &x) {
int arr[P.degree];
for (unsigned int i=0; i <= P.degree; i++) arr[i] = P[i];
Polynomial p(P.degree, arr);
std::cout << p << std:: endl; // just for debugging
return p;
}
I am testing the code in my main:
int g[] = {-1, 0, 1, 1, 0, 1, 0, 0, -1, 0, -1};
Polynomial P_g = Polynomial(10, g);
std::cout << P_g << std::endl;
Polynomial P_g_3 = P_g*3;
std::cout << P_g_3[0] << std::endl;
std::cout << P_g_3[1] << std::endl;
std::cout << P_g_3[2] << std::endl;
std::cout << P_g_3[3] << std::endl;
std::cout << P_g_3[4] << std::endl;
std::cout << P_g_3[5] << std::endl;
std::cout << P_g_3[6] << std::endl;
std::cout << P_g_3[7] << std::endl;
std::cout << P_g_3[8] << std::endl;
std::cout << P_g_3[9] << std::endl;
std::cout << P_g_3[10] << std::endl;
std::cout << P_g_3 << std::endl;
But the output in the console is something totally different then what I expect:
-1,0,1,1,0,1,0,0,-1,0,-1
-1,0,1,1,0,1,0,0,-1,0,-1
-1
0
0
0
0
0
-2002329776
32767
-516177072
32766
539561192
0,32766,539581697,32767,-2002329776,32767,1,0,243560063,1,-2002329776
Although notice that the inner cout statement from within the overloaded operator returns a correct polynomial. Only when the program exits that function the coefficients get screwed... Moreover the two printing strategies are not even consistent with themselves. What is going on?
Analysis
Your Polynomial class is rather unusual in that it does not own its own data. While this is not inherently wrong, it is almost always an unwise approach.
As an illustration, look at the variables in your main function. The data for the polynomial P_g is stored in the array g. The variable g serves no purpose other than storing that data, so its name is clutter. There is also a consistency concern here, because if someone were to change an element of g, then P_g would also change. Even worse, if g were to cease to exist while P_g was still around, you would have a polynomial without access to its data!
Fortunately, local variables are destroyed in the reverse order of creation, so P_g will be destroyed before g. However, no such luck intervenes when you invoke operator*. In that operator, the polynomial p stores its data in the local variable arr. So far, the situation is the same as in main(). Until you return p. At that point, p is copied/moved into the calling scope, and that copy uses the same data as the original. The array arr gets destroyed, yet the returned object still tries to access arr for its data. The returned object, P_g_3, has a dangling pointer.
When you try to access the data of P_g_3, undefined behavior occurs. In some cases, you might see the behavior you expect. In this case, garbage values were produced. From one perspective, your result is the more desirable one since you were able to detect that a problem exists, which allowed you to attempt to fix it. Far more insidious is the undefined behavior that performs as you expect when you run the program, but not when someone else does.
Solution
The usual approach is to have objects own their own data. Often, this is exclusive ownership, so that the data cannot change without going through the object.
A first refinement would be to move the data-holding arrays into the objects. The main obstacle is that you do not know in advance how large the array is. This calls for dynamic memory allocation. You could start down this road without changing the data members of your class; a first step might be to initialize coefficients to memory allocated with new rather than assigning it arr. This leads to the need to follow the Rule of Three. Unfortunately, this is a bit of work to do correctly, especially since you have chosen to track the degree of the polynomial instead of the size of the array.
Fortunately, storing data of unknown length is a common concern, common enough that the standard library provides tools to automate most of the details. One such tool is std::vector. If you change the type of coefficients from int* to std::vector<int>, then Polynomial objects will be able to own their own data, plus the Rule of Three becomes the Rule of Zero. (That is, the compiler-generated destructor and copy methods will suffice.) Your operator* could simply make a copy of the incoming Polynomial, then iterate over the copy's vector to make changes.
As an added benefit, you no longer need to track degree manually, as the degree of non-zero polynomials will be coefficients.size() - 1. (Well, there is a complication if the leading coefficient is zero, but that's also an unhandled concern for your original implementation.) This demonstrates one reason a class will often keep its data members private. If you had made the data member private and instead defined a degree() method, you could change how the degree is determined without modifying any code that uses Polynomial.
Note:
If you use range-based for loops with your vectors, the example code would have no need to look at the degree of a polynomial. You would be providing the member function for the benefit of code external to the class.

what does vector.size mean?

I wonder about this code
vector<pair<int,int>> map;
std::cout << "hello"<< std::endl;
map.push_back(make_pair(1,2));
map.push_back(make_pair(3,4));
map.push_back(make_pair(5,6));
map.resize(0);
std::cout << map[0].first
<< map[0].second << std::endl;
std::cout << map[2].first << std::endl;
std::cout << map.size() << std::endl;
std::cout << map.capacity() << std::endl;
I resize the map to size 0, but the result shows like this:
hello
12
5
0
4
Why do I get this?
Size of the vector (objects it contains) is not necessarily equal to its capacity (storage space allocated for it)
Looking at http://www.cplusplus.com/reference/vector/vector/size/, you can notice this statement: "This is the number of actual objects held in the vector, which is not necessarily equal to its storage capacity."
If you check you can see the following: http://www.cplusplus.com/reference/vector/vector/capacity/ "This capacity is not necessarily equal to the vector size. It can be equal or greater, with the extra space allowing to accommodate for growth without the need to reallocate on each insertion."
I hope this answers your question
Besides the thing about the vector capacity in the other answer, accessing out of bounds indexes on vectors with the bracket operator (instead of at(), which provides bound checking) produces undefined behavior.
In other words, the behavior is not defined in the standard and can change based on things like your compiler. In your case, it apparently did not crash and outputted the values even after they're no longer in the vector.
Needless to say, you want to make sure your program is free of undefined behavior.

Iterate through vector of objects c++

I've been struggling with this problem so I hope someone can help me.
I am creating a vector of objects and I would like to access elements of this vector but when I push back en element into the vector and try to access it, it doesn't work.
Thank you for your answers.
class reserve{
private:
vector<float> coordinates;
public:
reserve(const reserve &);
void addACoordinate(float);
void readCoordinates();
int getDim();
};
reserve::reserve(const reserve &w){
int i;
for(i=0; i<coordinates.size(); i++){
coordinates[i] = w.coordinates[i];
}
}
void reserve::addACoordinate(float c){
coordinates.push_back(c);
}
void reserve::readCoordinates(){
int i;
cout << "the coordinates are : ";
for(i=0; i<coordinates.size(); i++){
cout << coordinates[i] << " ";
}
cout << endl;
}
int reserve::getDim(){
return coordinates.size();
}
Then I create a reserve with 2 coordinates and push it into the reserves vector.
vector<reserve> reserves;
reserve r;
r.addACoordinate(1.9);
r.addACoordinate(1.9);
r.getDim();
reserves.push_back(r);
cout << "size of reserves " << reserves.size() << endl;
for (vector<reserve>::iterator k = reserves.begin(); k != reserves.end(); ++k) {
k->getDim();
}
But the output of the iteration is 0, instead of 2. I don't understand why I am not accessing the reserve r.
The shown copy constructor is completely broken:
reserve::reserve(const reserve &w){
int i;
for(i=0; i<coordinates.size(); i++){
The newly-constructed coordinates class member is always completely empty when the copy-constructor runs. It obviously won't magically have any content right from the start, so coordinates.size() will always be zero here. The copy constructor will never actually copy the element that's being used to copy from, and the alleged "copy" of it will always have an empty vector. And changing this to w.coordinates.size() will result in memory corruption, unless you also replace the assignment in the loop with a push_back(). Speaking of push_back()...
reserves.push_back(r);
push_back() attempts to copy r into the vector, here. That's it's job. Guess what's going to be used to do that? Why, the broken copy constructor, of course. Even if r has an initialized coordinates vector, the broken copy constructor will ensure that reserves will end up with a class instance with a completely empty coordinates vector.
You can completely get rid of the copy constructor, here. It serves no useful purpose, and the default copy constructor will do everything correctly.
If you need to manually implement a copy constructor for your homework assignment, fix it so it properly push_back()s the values from the class instance being copied from, or manually copies the class members itself, whatever you need to do the job.

Pass array to function without so it would not change original array no matter what

I have a function that performs some magic on the array that I am passing. But the original array should be intact. Unfortunately it is changing its content based on what is happening in the array.
Can you help me, please?
Function:
void test(int* array) {
array[0] = 1; // EDIT: Added missing line
std::cout << "Inside: " << array[0] << endl;
}
int main() {
int *testArray = new int[1];
testArray[0] = 0;
std::cout<<testArray[0]<<endl;
test(testArray);
std::cout << "Outside: " << testArray[0] << endl;
}
Current result is:
0
Inside: 1
Outside: 1
Result I would want to have:
0
Inside: 1
Outside: 0
Is this possible?
It sounds like you want to pass array by value not by reference. You are passing pointer to a first element here. So, any changes which you perform to that array inside that function will be reflected to original array.
The other problem is you haven't posted fair amount of code regarding the problem you want to solve. I am assuming you want functionality like this.
See live demo here.
#include <iostream>
void test(const int* array) {
array[0]=1;
std::cout << "Inside: " << array[0] << std::endl;
}
int main() {
int *testArray = new int[1];
testArray[0] = 0;
std::cout<<testArray[0]<<std::endl;
test(testArray);
std::cout << "Outside: " << testArray[0] << std::endl;
delete[] testArray;
}
Compiler will give you following errors:
Error(s):
source_file.cpp:4:13: error: read-only variable is not assignable
array[0]=1;
~~~~~~~~^
1 error generated.
You should not use new[] to allocate dynamic arrays in C++. 99% of the time you should be using std::vector If you want dynamic array in C++.
Avoid using C compatibility features...
void test( std::array<int, 1> a )
{
a[0] = 1; // fine
std::cout << "Inside: " << a[0] << endl;
};
int main()
{
std::array<int, 1> testArray;
testArray[0] = 0;
std::cout<<testArray[0]<<endl;
test(testArray);
std::cout << "Outside: " << testArray[0] << endl;
}
If you need the size determined at runtime, use std::vector instead of std::array.
EDIT: As others have pointed out, it seems like you want to either pass the array by value instead of by reference, thus copying the elements of the array and modifying only the copy, or you want to avoid modifying any part of the array altogether. I'll elaborate on both parts a bit more:
In C++, there is near to no distinction between arrays and pointers. Note that both your variable testArray and your parameter array are pointers to the beginning of an array. If you use array to modify any part of the underlying array, what you actually do is modify the memory are that is described by both testArray and array. If you don't want to modify any part of the array at all, it would be helpful to use the const qualifier, as Destructor already wrote in his answer. If you however want to keep the original array but still want to make some modifications inside the function, the following still applies:
To keep the array from being modified, the only general way that works is to copy all of its elements by creating a new array of the same size, copying all elements from the input array to the copy and then working only on the copy, which should be deleted after the function has finished.
My personal answer:
I would recommend that you look into some of C++'s data structures, especially std::vector. If you pass it by value (not by reference), vector takes care of all the necessary copy operations I just described and in all cases, you can use it in the same way as an array, while it provides lots of additional features (i.e. dynamic size, deletion and insertion of elements, simplified iteration, ...).

Adding vector to 2D vector, and keeping reference to the last vector

I am writing a program and there was a very subtle error that was hard to recognize.
I examined the program for hours and it looks like it's from my misuse of resize() in allocating a new vector in 2D vector, from my misuse of back() in vector, or from updating a reference variable.
I wrote a simpler code that contains similar problem in my original program for demonstration:
int main() {
vector<vector<int>> A(1);
vector<int> &recent = A.back();
recent.emplace_back(50);
cout << A.back()[0] << endl; //prints 50
A.resize(2);
A[1] = vector<int>();
cout << A.size() << endl; //prints 2
recent = A.back();
cout << A[1].size() << endl; //prints 0
recent.emplace_back(20); //Segmentation fault occurs!!
cout << A[1][0] << endl;
}
Segmentation fault occurs when I tried to emplace_back(20), although in my original program it doesn't throw any error and doesn't emplace the element either.
Possible cause of problem, in my opinion is:
I used resize() to allocate a new vector after the current last position of the 2D vector A, because I didn't know how to emplace_back() an empty vector.
2, 3. In recent = A.back();, I'm not sure if I am updating the reference variable(defined as vector<int> &recent) correctly, and if back() gives the correct reference to the newly allocated vector at the end of the 2D vector A.
The logic looked perfectly fine, but obviously I am doing something wrong.
What am I doing wrong, and what can I do instead?
References in C++ cannot be "updated". The call to resize may (and likely will) invalidate any reference to the original content of the vector. Thus recent is a dangling reference after A.resize(2);.
When creating the initial A here
std::vector<std::vector<int>> A(1);
the outer vector is required to be able to store one single vector.
If you add another std::vector<int> to A the first element of A is likely to move to another memory location. Since recent will always refer to the old memory location you see the segfault.
See 'c++ Vector, what happens whenever it expands/reallocate on stack?' for how vectors work.
On the question how to circumvent this:
If you know the size of the vector in advance you could use reserve to prevent the vector A from reallocating its contents. You'd nevertheless face the problem that references cannot be "reassigned". You can always use A.back() to refer to the last element.
You can use a function taking a reference argument which will be bound upon calling the function:
void do_stuff(std::vector<int> & recent)
{
// do stuff with recent
}
std::vector<std::vector<int>> A;
while (condition)
{
// add whatever to A
A.emplace_back(std::vector<int>{});
// do stuff with last element
do_stuff(A.back());
}
Another way to do it is with scope:
std::vector<std::vector<int>> A(1);
{
std::vector<int> &recent = A.back();
recent.emplace_back(50);
std::cout << A.back()[0] << std::endl; //prints 50
A.resize(2);
} // recent goes out of scope here
std::cout << A.size() << std::endl; //prints 2
{
std::vector<int> &recent = A.back(); // another recent indepedant of first one
std::cout << A[1].size() << std::endl; //prints 0
recent.emplace_back(20);
std::cout << A[1][0] << std::endl; // prints 20
}
Let's step through the code line by line.
vector<vector<int>> A(1);
vector<int> &recent = A.back();
Here we create a vector with one default-constructed vector<int> as its contents. We then bind a reference to the last and only element.
recent.emplace_back(50);
cout << A.back()[0] << endl; //prints 50
We now emplace 50 into the sole vector and print it.
A.resize(2);
Now we resize the vector. If space needs to be reallocated, all iterators, pointers and references to the contents are now invalid.
A[1] = vector<int>();
cout << A.size() << endl; //prints 2
This is fine, as there is enough space in A.
recent = A.back();
BANG
This assignment doesn't rebind recent, it tries to assign A.back() to the referencee. If space was reallocated for A, recent is no longer a valid reference, so we run off into the realm of undefined behaviour.
Quite honestly, using A.back() directly rather than maintaining a reference to it is probably your best bet. If you absolutely want to hold some kind of reference to the end, this is a reasonable use of a non-owning pointer.
From the discussion in the comments, it appears that your original problem was:
vector<vector<int>> very_long_name_that_cannot_be_changed;
and that you want a shorthand notation to access the last element of this:
auto& short_name = very_long_name_that_cannot_be_changed;
short_name.resize(100); // will expand the vector, but not change the reference
short_name.back().emplace_back(20); // presto, quick accesss to the last element.
This is proof against resizing, because the reference just tracks the vector, not its last element.