Why can I still access vector data after resizing? - c++

The following code doesn't throw an error:
int main()
{
typedef std::vector<int> intstack;
intstack mystack;
mystack.push_back(7);
mystack.push_back(8);
mystack.push_back(9);
mystack.pop_back();
std::cout << mystack.size(); //prints 2
std::cout << mystack[2]; // prints 9
return 0;
}
I would have thought the line std::cout << mystack[2] would throw an error because the vector has been resized by the pop_back operation. Why is the data still accessible? Is it because the data in the underlying array is still there and the vector pop_back operation only modifies the iterators?

std::vector operator[] does not perform range checks.
the at() member function does.
Your line std::cout << mystack[2] has undefined behavior.

Related

std::vector - why does the element still exist after invoking delete?

I have this code I don't understand why I need to delete and then pop_back().
Can I do it in 1 operation only ?
struct T
{
T(int n):x(n){};
int print() {
return x;
};
private:
int x;
};
int main(int argv,char** argc)
{
std::vector t = { new T(1),new T(2)};
delete t.back();
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
t.pop_back();
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
return 0;
}
The output - as you can see after delete it looks like the vector is still holding the element witout the object:
2
179185600
1
1
My question is why do I need delete and then remove , can't same operation be done in single command ?
1. The issues in your code:
This line:
delete t.back();
Is not removing any element from the std::vector. Your std::vector is holding pointers, and it will continue to hold the same pointers.
What the line above does is deallocate the object pointed by the element in the std::vector.
This line (the 1st occurance):
std::cout << t.back()->print() << std::endl;
Invokes UB (Undefined Behavior) because you derefernce a pointer after it has beed deleteed.
Then after:
t.pop_back();
The last pointer (the one that you deleteed, i.e. freed) is removed from the std::vector, and t.back() is the other pointer you inserted, which is still valid.
2. A different approach - avoid pointers:
Having wrote all that, in this case you do not actually need to deal with pointers at all.
You can use std::vector<T>, (instead of T* like you did) and store the elements by value. You will not need to new or delete anything.
Code example:
#include <vector>
#include <iostream>
struct T
{
T(int n) :x(n) {};
int print() { return x; };
private:
int x;
};
int main(int argv, char** argc)
{
std::vector t = { T{1}, T{2} };
std::cout << t.size() << std::endl;
std::cout << t.back().print() << std::endl;
t.pop_back();
std::cout << t.size() << std::endl;
std::cout << t.back().print() << std::endl;
return 0;
}
Output:
2
2
1
1
3. Using smart pointers:
If you need to use pointers, use smart pointers (like std::unique_ptr, std::shared_ptr) instead of raw ones. The benefit is that the deallocation is done automatically.
std::unique_ptr is the more light-weight and should be the default one. Use std::shared_ptr if you need shared ownership.
Code example (with the same output as above):
#include <vector>
#include <iostream>
#include <memory>
struct T
{
T(int n) :x(n) {};
int print() { return x; };
private:
int x;
};
int main(int argv, char** argc)
{
std::vector<std::unique_ptr<T>> t;
t.push_back(std::make_unique<T>(1));
t.push_back(std::make_unique<T>(2));
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
t.pop_back();
std::cout << t.size() << std::endl;
std::cout << t.back()->print() << std::endl;
return 0;
}
In your code there are two distinct types of objects to be considered.
The elements in the vector are pointers to T, T*. The lifetime of those pointers is managed by the vector. You can add or remove them via member methods of the vector.
Then there are the objects you decided to manage manually via the raw pointers in the vector. They are instances of T. Because you used new to create them you must use delete to delete them.
The vector cannot know about this relation between the pointers (the elements in the vector) and the T objects. It was your decision to manage them manually. You do not have to do that.
Chances are high that you either want a std::vector<T>. Or if for some reason (there is none in your code) you need to have the Ts allocated dynamically, then you would use a std::vector<std::unique_ptr<T>>.
Now this line:
delete t.back();
deletes the T, but the pointer is still in the vector. It is an invalid pointer, the object is was pointing to is no longer alive. When you call t.back()->print() your code invokes undefined behavior. You cannot use an already deleted object. If you do, anything can happen. This has nothing to do with the vector, it is similar to
T* t = new T(); // create object
delete t; // delete it
t->print(); // use it -> !!! undefined behavior !!!
Instead of this you should write
T t;
t.print();
In case you are coming from Java, you must unlearn to use new to create objects. The way to create objects in C++ is not via new.
My question is why i need delete and then remove , can't same
operation done in single command ?
There would be 6 answers from me to your question and Let this be your introduction to Pointers , Stack and the Heap.
1.) new operator "Allocates" memory on the heap not the stack,Create that Object (Using it's Constructors) then return a Pointer to the Object that is now on the Heap, hence the need for using the delete operator to "De-allocate" the memory you have requested and "Destroy" the created Object.
2.) delete "De-Allocates" the memory from heap and "Destroy" the created Object, and it does not remove it from the vector
3.)t.pop_back() will remove the Pointer element from the vector but will not de-allocate and Destroy the object the Pointer is Pointing too.
4.) It can't be done with one line since you have requested to allocate a Memory on the heap that can fit struct T inside via the new keyword. By using the keyword new the vector std::vector t is not storing an Object struct T,[std::vector<T>] instead storing Pointers to an Object of struct T [std::vector<T*>] since you did not explicitly Say what the Vector would Hold.
5.) Heap Allocated memory is perpetual , meaning it will always be there and labeled "In Use". Neither the Program, Runtime nor the O.S. can use it to allocate a new Memory Region on the heap unless you explicitly de-allocate and destroy it when using delete, Essentially saying "I'm done with this memory location thank you You may now destroy this object and re-use the memory)". or the Program Closes / Ends. So every new or new[] must be accompanied by delete or delete[] somewhere in the code when that variable is no longer in use anywhere in the program.
6.) After you understand the behavior of Heap / Dynamic Variables have a look at Smart Pointers. Which Handles the destruction of an object for you automatically. If you are coming from Managed Languages, you might want to read up on "Object Lifetimes" on C++.
The following Code will help you visualize my answer.
#include <vector>
#include <iostream>
struct T
{
T(int n):x(n){};
int print() {
return x;
};
// Replaces the Value of X
void SetX(int n){x=n;};
private:
int x;
};
int main(int argv,char** argc)
{
// We explicitly Say that the Vector is holding a Pointers to an object struct T
std::vector<T*> t;
// Insert New Elements to the Vector
t.push_back(new T(1));
t.push_back(new T(2));
// Will show that there are 2 elements in the vector.
std::cout << "Size of Vector Is " << t.size() << std::endl << std::endl;
// Assign the Last Element to a Pointer of T.
T* pointerToT = NULL;
pointerToT = t.back();
// Print the Memory Address and value of pointerToT and the Last Element
// And we can see they are the same location and holds the same value.
std::cout << "The Memory Location of pointerToT is " << pointerToT << std::endl;
std::cout << "The Memory Location of t.back() is " << t.back() << std::endl;
std::cout << "The Value of X in pointerToT is " << pointerToT->print() << std::endl;
std::cout << "The Value of X in t.back() is " << t.back()->print() <<std::endl << std::endl;
//Removes the Last Element of the Vector
t.pop_back();
// Will show that there is only 1 element in the vector.
std::cout << "Size of Vector Is " << t.size() << std::endl << std::endl;
// Print the Memory Address of pointerToT and the Value of X
// And as we can see pointerToT is still holding the same location
// and still holding the value 2, since the program knows that
// The memory Location is "Still" in use and not yet De-Allocated
// ready to be re-used and the object not yet destroyed.
std::cout << "The Value of X after pop_back() is " << pointerToT->print() << std::endl;
std::cout << "The Memory Location of pointerToT after pop_back is " << pointerToT << std::endl << std::endl;
//De-Allocate the Memory and Destroy the Object that was created by t.push_back(new T(2));
delete pointerToT;
// Prints the value of X, that is stored in the memory on the heap that it's pointing to.
// This Value may or may not be 2 if it is now used other parts of the Code
// which we call an Undefined Behaviour.
// On a Larger Program this could and would Cause a Segmentation fault or
// an Access Violation since this is now a Memory Region that is not explicitly
// Allocated for pointerToT , to the Member Variable X, nor
// The Last Element of the Vector and may now be in use by other variables and that the object is Destroyed already destroyed.
std::cout << "The Memory Location of pointerToT after delete is " << pointerToT << std::endl;
std::cout << "The Value of X after Delete is " << pointerToT->print() << std::endl;
// This is also an undefined Behaviour since you are now accessing and modifying
// a Memory Location that is not Allocated for pointerToT . But would show
// that the value of X is now 10. So only delete(Destroy)when you are sure you are not going to be
// accessing that variable again.
pointerToT->SetX(10);
std::cout << "The Value of X after SetX() is " << pointerToT->print() << std::endl;
return 0;
}

Is it Safe to Assign vector With operation= vector() in C++

Is it safe to assign vector later after initialization.
Let say i have a global vector variable. But i don't want to initialize the value at the beginning.
#include <iostream>
#include <vector>
using namespace std;
vector<int> globalVector;
int myNumber=123;
void setVector()
{
// Is it safe to set the vector as shown below ?
globalVector = vector<int>{1,2,3,4};
}
int main(int, char**) {
setVector();
for (int x=0; x<globalVector.size();x++)
{
cout << "Val = " << globalVector[x] << endl;
}
std::cout << "Hello, world! : " << myNumber << endl;
return 0;
}
on VSCode i can see some information said :
std::vector<int> &std::vector<int>::operator=(std::vector<int> &&__x)
+2 overloads
%Vector move assignment operator.
Parameters:
__x – A %vector of identical element and allocator types. The contents of __x are moved into this %vector (without copying, if the allocators permit it). Afterwards __x is a valid, but unspecified %vector. Whether the allocator is moved depends on the allocator traits.
The description said "move without copying". will the globalVector corrupt when the program exit from function setVector ?
Yes that is safe, although
The notation globalVector = {1,2,3,4}; is clearer.
It's not thread-safe.
Use globalVector.at(x) rather than globalVector[x] unless performance really matters, as the behaviour of the latter can be undefined for some values of x. In this particular case, a range-for loop would be better still: for (auto&& i: globalVector).
The description said "move without copying". will the globalVector corrupt when the program exit from function setVector ?
It means that operator= moved content of new vector without copy operation. The vector used for initialization is invalid after that operation. However it doesn't impact you since it is the object used only for initialization so is destroyed just after that.
Yes, it is totally safe, but I recommend you not to use global vector
instead write
int main() {
std::vector<int> globalVector = vector<int>{1,2,3,4};
for (int i=0; i<globalVector.size();i++) {
cout << "Val = " << globalVector.at(i) << '\n';
}
std::cout << "Hello, world! : " << myNumber << '\n';
return 0;
}

Why referenced vector address cannot be dereferenced in cpp?

I am trying to dereference a referenced vector address as follows:
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> p;
p.push_back(1);
p.push_back(2);
p.push_back(3);
p.push_back(4);
p.push_back(5);
p.push_back(6);
cout << (*(&p)) << endl;
cout << (*(&p + 3)) << endl;
return 0;
}
But it fails.
Expecting output:
1
4
std::vector<int> p; is an object that manages consecutive storage of elements of type int.
&p would be an address of such an object. What that object contains is unspecified. You can expect a vector object to contain, e.g. the pointer to an array of elements allocated on the heap, the current size and capacity.
To get a pointer to the underlying elements, use p.data().
To access a specific element of a vector can use the overloaded operator[] (e.g. p[0], p[3]).
An iterator (e.g. p.begin()) can also be used as an abstraction around a pointer to an element:
int main() {
vector<int> p;
p.push_back(1);
p.push_back(2);
p.push_back(3);
p.push_back(4);
p.push_back(5);
p.push_back(6);
cout << (*(p.begin())) << endl;
cout << (*(p.begin() + 3)) << endl;
}
The benefit of using iterators in place of raw pointers is that the access is bounds-checked in debug builds (in VC++ at least), and it will seamlessly work with other types of sequential containers.

c++: std::vector of std::vector inside a struct

I need to create a struct that sotres a
std::vector<std::vector<int>> that will contain 4 vectors of ints.
I tried the declaration I usually use for vector of vectors:
struct myStruct{
std::vector<std::vector<int>> myVector(4);
};
but, when I compile, I get this error:
myProgram.cpp:79:52: error: expected identifier before numeric constant
std::vector<std::vector<int>> myVector(4);
^
myProgram.cpp:79:52: error: expected ‘,’ or ‘...’ before numeric constant
I tried to declare the vector in the struct and then reserve 4 elements in the main(), in the following way:
struct myStruct{
std::vector<std::vector<int>> myVector;
};
int main(){
myStruct s;
s.myVector.reserve(4);
s.myVector[0].push_back(1);
return 0;
}
In this way it compiles without errors, but I get a segmentation violation as soon as I try to push_back.
What is the proper way to do this task? And why can't I use the first declaration to specify the size of myVector?
Thank you! :)
A default member initializer inside a class or struct must have an = token and/or {curly braces}.
std::vector<std::vector<int>> myVector{4};
[Note this would be trickier if the type were just std::vector<int>, since curly braces for a vector imply a sequence of elements. std::vector<int>{4} is a vector with size one whose one element is 4, not a vector of four zeroes. But here it's fine because {4} can't convert to std::initializer_list<std::vector<int>>, so that constructor overload isn't eligible, and the vector(size_type) constructor does win.]
The example program has undefined behavior because reserve does not change the size or create any elements. So s.myVector[0] is invalid since the vector is still empty. Remember, reserve is just a setup hint for the vector. Any valid program that uses reserve would still be valid if you removed all the reserve calls.
Using resize instead would do what you seem to mean: make the size of myVector equal to 4, by creating 4 empty element vectors. Then the push_back would add the number 1 to the first of those vectors, resulting in data {{1}, {}, {}, {}}.
int main(){
myStruct s;
s.myVector.resize(4);
s.myVector[0].push_back(1);
return 0;
}
struct myStruct {
std::vector<std::vector<int>> myVector{4};
};
int main() {
myStruct s;
s.myVector[0].push_back(1);
s.myVector[0].push_back(2);
s.myVector[0].push_back(3);
s.myVector[0].push_back(4);
s.myVector[1].push_back(11);
s.myVector[1].push_back(21);
s.myVector[1].push_back(31);
s.myVector[1].push_back(41);
cout << s.myVector[0][0] << " " << s.myVector[0][1] << " " << s.myVector[0][2] << " " << s.myVector[0][3] << " " << endl;
cout << s.myVector[1][0] << " " << s.myVector[1][1] << " " << s.myVector[1][2] << " " << s.myVector[1][3] << " " << endl;
return 0;
}
What is the proper way to do this task?
Hope this will answer your question.

Why is this std::vector being cleared when program enters main function?

The problem I'm having is that I am pushing an element into a vector at initialisation when all the static variables are initialised, and then when it enters the main function the vector resets to 0, as if it has cleared. In my case the vector was in a different CPP, but this also shows the problem:
#include <iostream>
#include <vector>
struct List
{
static std::vector<int> listVector;
};
struct Foo
{
Foo()
{
std::cout << List::listVector.size() << '\n'; // Prints 0
List::listVector.push_back(1);
std::cout << List::listVector.size() << '\n'; // Prints 1
}
};
Foo fooObj;
std::vector<int> List::listVector;
int main()
{
std::cout << List::listVector.size() << '\n'; // Prints 0
List::listVector.push_back(2);
std::cout << List::listVector.size() << '\n'; // Prints 1
}
The first element I added to the vector has been lost. I know one has to be careful with initialisation order of static global variables, but I can't understand why the vector is being cleared. I'm tempted to think that when the Foo constructor runs it adds an element to the vector, but the vector hasn't been created yet, because it's written on the line after the Foo object is created. However, if this is the case, just what vector am I adding into when I do so in the constructor and it prints out a size of 1?
I'm kind of confused.
I'm tempted to think that when the Foo constructor runs it adds an element to the vector, but the vector hasn't been created yet, because it's written on the line after the Foo object is created.
Yes, that's exactly right. The fooObj constructor just accesses the memory where the vector will be constructed, but it hasn't been constructed there yet. (So the program has undefined behaviour, and must be fixed)
However, if this is the case, just what vector am I adding into when I do so in the constructor and it prints out a size of 1?
The compiler simply interprets the memory as being a valid vector, because it has no way to know otherwise. That just happens to work, because the memory that the global will be constructed in is initially zero, because the execution environment ensures that all static objects' memory is initially zero, which happens to be the same as the default-constructed state (for your implementation's definition of std::vector). The program has no way to know that the memory location containing all-zeros is not a valid vector yet.
Later the constructor for the vector runs and re-initializes the memory, to the default-constructed state.
Here is an example showing what your program does: interpreting raw memory containing all zeros as a vector, and adding elements to that phantom vector (which doesn't really exist), then actually constructing a vector in that memory. Anything added to the phantom vector is lost once the real vector is created.
#include <iostream>
#include <vector>
int main()
{
// initialize a block of memory to zero:
alignas(std::vector<int>) char memory[sizeof(std::vector<int>)] = {};
// use that memory as a vector, even though we haven't created any vector
// (this is undefined behaviour! there is no vector yet!):
std::vector<int>& vec = *reinterpret_cast<std::vector<int>*>(memory);
vec.push_back(1);
// the non-existent "phantom vector" has size 1:
std::cout << vec.size() << std::endl;
// now use "placement new" to construct an empty vector in that memory:
new (memory) std::vector<int>();
// the real vector is empty, the element in the phantom vector is lost:
std::cout << vec.size() << std::endl;
}
To fix your program you need to initialize the vector before anything refers to it (specifically, before the fooObj constructor tries to use it, by defining it before fooObj).
if you change the code to
#include <iostream>
#include <vector>
namespace List
{
static std::vector<int> listVector;
}
struct Foo
{
Foo()
{
std::cout << List::listVector.size() << '\n'; // Prints 0
List::listVector.push_back(1);
std::cout << List::listVector.size() << '\n'; // Prints 1
}
};
Foo fooObj;
//std::vector<int> List::listVector;
int main()
{
std::cout << List::listVector.size() << '\n'; // Prints 0
List::listVector.push_back(2);
std::cout << List::listVector.size() << '\n'; // Prints 1
}
it should work. I'm not in global variables (I don't use them) but I think the problem that the struct param don't make it real global. Maybe a other user can explain it ...
Edit: you can also remove the namespace, i make it so you can let the List::
Edit2: if you want to use with struct than it works with
struct List
{
std::vector<int> listVector;
};
static List GlobL;
And than use GlobL.listVector, than the struct obj ist static and not the parameter of the struct.
You have to understand that your program doesn't run from top to bottom. Every programm will start at your main() function. All the code above main() will basically get ignored if it doesn't get called in the main() function.
Questions like these should not be asked here though. It seems like you are a beginner and you should start by reading yourself more into the subject before asking questions.