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 delete
ed.
Then after:
t.pop_back();
The last pointer (the one that you delete
ed, 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;
}