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

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;
}

Related

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.

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.

push_back keeps rewriting all entries in the vector to the item pushed_back?

I am currently trying to make a light copy of a vector. A light copy meaning that the content of the copy, is a vector of pointer of the original vector. I am for some reasons having problems doing so... Each time I push_back a new entry into the copy vector, I seem to overwrite all the entries in the vector, to the element I just push_back, why is this happening:
MWE:
// This file is a "Hello, world!" in C++ language by GCC for wandbox.
#include <iostream>
#include <cstdlib>
#include <experimental/filesystem>
#include <vector>
#include <algorithm>
struct abstract_data_structure
{
int x;
int y;
std::vector<int> points;
std::string name;
abstract_data_structure(int x, int y , std::vector<int> points, std::string name)
{
this->x= x;
this->y = y;
this->points = points;
this->name = name;
}
};
int main()
{
std::vector<abstract_data_structure> storage;
std::vector<abstract_data_structure*> copy_of_storage;
std::srand(std::time(0));
for (int i = 0; i< 5 ; i++)
{
int x = std::rand();
int y = std::rand();
std::vector<int> vecOfRandomNums(10);
std::generate(vecOfRandomNums.begin(), vecOfRandomNums.end(), []() {
return rand() % 100;
});
std::string name = "something"+std::to_string(i);
abstract_data_structure something(x,y,vecOfRandomNums,name);
storage.push_back(something);
}
std::cout << storage.size() << std::endl;
std::cout << "Make the copy" << std::endl;
for (auto element : storage)
{
std::cout << "in storage" << std::endl;
std::cout << element.name << std::endl;
copy_of_storage.push_back(&(element));
std::cout << "in copy storage" << std::endl;
for (auto copy_element: copy_of_storage)
{
std::cout << copy_element->name << std::endl;
}
}
}
https://wandbox.org/permlink/Xn96xbIshd6RXTRa
which outputs this:
5
Make the copy
in storage
something0
in copy storage
something0
in storage
something1
in copy storage
something1
something1
in storage
something2
in copy storage
something2
something2
something2
in storage
something3
in copy storage
something3
something3
something3
something3
in storage
something4
in copy storage
something4
something4
something4
something4
something4
0
As one might see are all the entries in the copy vector, modified to point to last element inserted? why?
//***1***
for (auto element : storage)
{
std::cout << "in storage" << std::endl;
std::cout << element.name << std::endl;
//***2***
copy_of_storage.push_back(&(element));
std::cout << "in copy storage" << std::endl;
for (auto copy_element: copy_of_storage)
{
std::cout << copy_element->name << std::endl;
}
}
At ***1***, you're making a local copy of each variable.
At ***2***, you're taking the address of that local copy and saving it in the vector.
When you leave scope, the object has been destructed and no longer exists. So when you later try to read it, you get Undefined Behavior, which means you cannot guarantee the behavior that will take place.
What seems to be happening is that each time, you're taking the address of the local variable, and each iteration of the for-loop, that location of the variable is the same, so each address in the final copy vector is the same, and because the most recent copy is whichever entry in the storage vector you were most recently working with, that's the version that gets read by the pointer.
If you change ***1*** to for(auto & element : storage), your issue should be fixed.
The problem is a bit deeper than you may suspect. In
std::vector<abstract_data_structure> storage;
std::vector<abstract_data_structure*> copy_of_storage;
copy_of_storage cannot be a copy of storage without a lot of extra effort and probably dynamic allocation of abstract_data_structures.
copy_of_storage contains pointers and those pointers have to point to abstract_data_structures. These abstract_data_structures may or may not be copies.
The naive fix, swapping
for (auto element : storage)
for
for (auto & element : storage)
makes element a reference to an abstract_data_structure stored within storage. This means that element references a variable that has longer life than a single iteration of the for loop, but
copy_of_storage.push_back(&(element));
doesn't make a copy. It just points to the original abstract_data_structure inside storage. Sometimes this is useful, but when one list is supposed to be a copy of the other, it probably should directly refer to the other list.
For example, adding another abstract_data_structure to storage will invalidate the pointers. The contents of storage can be moved in the existing storage. The storage may be replaced with a larger block and the pointers left pointing to invalid memory. All sorts of nasty things can happen.
Instead, I recommend
std::vector<abstract_data_structure> storage;
std::vector<abstract_data_structure> copy_of_storage;
and later
for (auto & element : storage)
and
copy_of_storage.push_back(element);
Now you have a copy.
But... there are easier ways. std::vector is a very smart beast. You can
copy_of_storage = storage;
and storage will copy itself.
Recommended extra reading: What is The Rule of Three? This is not required for your example, but very very important to learn early in a programming career.

Expression must have a pointer type error

I have read the other similar posts, but still haven't found a way to solve my coding problem.
Here is the code:
void Foo(vector<Name> &obj){
vector<Name> *temp = 0;
temp = new vector<Name>;
if (!temp){
std::cout << "temp Allocation Error!" << std::endl;
exit(1);
}
temp->push_back(obj[n]);
std::cout << temp[0]->member_function() << std::endl;
}
Foo is a universal function.
I have a function Foo that takes a reference to a vector container. Within Foo there is a dynamic vector called temp.
I use push_back() to insert an obj into the temporary vector.
Then I wish to access that obj stored in the temporary vector in order to access its member function.
However this is where the compiler says that "expression must have pointer type".
Could somebody please explain how to rewrite this line of code.
std::cout << temp[0]->member_function() << std::endl;
temp[0]->member_function()
This treats temp as if it were an array of pointers-to-vector, which it's not.
You need to dereference temp before performing array subscripting on the result:
(*temp)[0].member_function()
Honestly, though, dynamic allocation here is pointless and is giving you a memory leak right now.
You have a vector of Name objects, and not Name*, but you use the "->" operator instead of "." which is what the compiler is telling you.
You should either try:
std::cout << (*temp)[0].member_function() << std::endl;
or make the vector elements Name*.
temp[0]->member_function()
would be correct if temp were a vector of pointers, but it isn't – it's a pointer to one vector.
And you can't use -> with a vector.
(It is equivalent to (*temp)->member_function().)
You can say
(*temp)[0].member_function()
but the better solution is usually to avoid dynamic allocation completely:
vector<Name> temp;
temp.push_back(obj[n]);
std::cout << temp[0].member_function() << std::endl;