Memory leaks in a pointer vector
I'm making a program that uses plenty of vectors containing pointers and I'm concerned that the way i delete the pointers might cause memory leaks down the line.
Here's for example how I add a bullet to the vector:
Bullet* aNewBullet;
aNewBullet = new Bullet(x,y,dirX,dirY,size,duration);
aNewBullet->assignTexture(btext);
bulletVector.push_back(aNewBullet);
And here's how i delete bullets from the vector (for example, if it exceeds its range)
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
bulletVector.erase(bulletVector.begin() + i);
else i++;
Am I deleting the bullet by telling the vector to erase?
Or should i do
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
delete bulletVector[i];
bulletVector.erase(bulletVector.begin() + i);
else i++;
instead? Does this mess up the vector size by deleting the pointer first, and then deleting the record from the vector again?
Also does deleting the pointer call the bullet destructor (~Bullet())?
c++ pointers vector memory-leaks
add a comment |
I'm making a program that uses plenty of vectors containing pointers and I'm concerned that the way i delete the pointers might cause memory leaks down the line.
Here's for example how I add a bullet to the vector:
Bullet* aNewBullet;
aNewBullet = new Bullet(x,y,dirX,dirY,size,duration);
aNewBullet->assignTexture(btext);
bulletVector.push_back(aNewBullet);
And here's how i delete bullets from the vector (for example, if it exceeds its range)
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
bulletVector.erase(bulletVector.begin() + i);
else i++;
Am I deleting the bullet by telling the vector to erase?
Or should i do
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
delete bulletVector[i];
bulletVector.erase(bulletVector.begin() + i);
else i++;
instead? Does this mess up the vector size by deleting the pointer first, and then deleting the record from the vector again?
Also does deleting the pointer call the bullet destructor (~Bullet())?
c++ pointers vector memory-leaks
3
Do you need to usenew
/delete
? Why not just usestd::vector<Bullet>
?
– CoryKramer
Nov 15 '18 at 13:52
Collections of raw pointers are just not a good idea. Either the collection owns the objects pointed to or it doesn't. If it does own them, why use pointers at all? If it doesn't own them, managing the lifetime of the objects becomes very complicated.
– David Schwartz
Nov 15 '18 at 14:42
add a comment |
I'm making a program that uses plenty of vectors containing pointers and I'm concerned that the way i delete the pointers might cause memory leaks down the line.
Here's for example how I add a bullet to the vector:
Bullet* aNewBullet;
aNewBullet = new Bullet(x,y,dirX,dirY,size,duration);
aNewBullet->assignTexture(btext);
bulletVector.push_back(aNewBullet);
And here's how i delete bullets from the vector (for example, if it exceeds its range)
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
bulletVector.erase(bulletVector.begin() + i);
else i++;
Am I deleting the bullet by telling the vector to erase?
Or should i do
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
delete bulletVector[i];
bulletVector.erase(bulletVector.begin() + i);
else i++;
instead? Does this mess up the vector size by deleting the pointer first, and then deleting the record from the vector again?
Also does deleting the pointer call the bullet destructor (~Bullet())?
c++ pointers vector memory-leaks
I'm making a program that uses plenty of vectors containing pointers and I'm concerned that the way i delete the pointers might cause memory leaks down the line.
Here's for example how I add a bullet to the vector:
Bullet* aNewBullet;
aNewBullet = new Bullet(x,y,dirX,dirY,size,duration);
aNewBullet->assignTexture(btext);
bulletVector.push_back(aNewBullet);
And here's how i delete bullets from the vector (for example, if it exceeds its range)
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
bulletVector.erase(bulletVector.begin() + i);
else i++;
Am I deleting the bullet by telling the vector to erase?
Or should i do
int i=0;
while (i<bulletVector.size())
if (bulletVector[i]->getDuration() ==0)
delete bulletVector[i];
bulletVector.erase(bulletVector.begin() + i);
else i++;
instead? Does this mess up the vector size by deleting the pointer first, and then deleting the record from the vector again?
Also does deleting the pointer call the bullet destructor (~Bullet())?
c++ pointers vector memory-leaks
c++ pointers vector memory-leaks
asked Nov 15 '18 at 13:51
martincitomartincito
163
163
3
Do you need to usenew
/delete
? Why not just usestd::vector<Bullet>
?
– CoryKramer
Nov 15 '18 at 13:52
Collections of raw pointers are just not a good idea. Either the collection owns the objects pointed to or it doesn't. If it does own them, why use pointers at all? If it doesn't own them, managing the lifetime of the objects becomes very complicated.
– David Schwartz
Nov 15 '18 at 14:42
add a comment |
3
Do you need to usenew
/delete
? Why not just usestd::vector<Bullet>
?
– CoryKramer
Nov 15 '18 at 13:52
Collections of raw pointers are just not a good idea. Either the collection owns the objects pointed to or it doesn't. If it does own them, why use pointers at all? If it doesn't own them, managing the lifetime of the objects becomes very complicated.
– David Schwartz
Nov 15 '18 at 14:42
3
3
Do you need to use
new
/delete
? Why not just use std::vector<Bullet>
?– CoryKramer
Nov 15 '18 at 13:52
Do you need to use
new
/delete
? Why not just use std::vector<Bullet>
?– CoryKramer
Nov 15 '18 at 13:52
Collections of raw pointers are just not a good idea. Either the collection owns the objects pointed to or it doesn't. If it does own them, why use pointers at all? If it doesn't own them, managing the lifetime of the objects becomes very complicated.
– David Schwartz
Nov 15 '18 at 14:42
Collections of raw pointers are just not a good idea. Either the collection owns the objects pointed to or it doesn't. If it does own them, why use pointers at all? If it doesn't own them, managing the lifetime of the objects becomes very complicated.
– David Schwartz
Nov 15 '18 at 14:42
add a comment |
4 Answers
4
active
oldest
votes
In the first code example you are not deleting any Bullet
object. Erasing vector
does only remove the pointers, not delete the pointed to object.
Your second example does properly delete Bullet
s (not all of them given the conditionals and loop setup), but only if you do the necessary deletion at all points where the vector is modified and manually assure that a pointer is never deleted twice (e.g. because it is present in two vectors). This is not how containers are supposed to be used.
If you really want to store pointers and have the vector own them, then you should use std::vector<std::unique_ptr<Bullet>>
which will properly delete the Bullet
objects when the vector is erased. However the vector will become non-copyable (only movable).
If however the vector is supposed own the Bullet
s anyway, then you can simply store them directly in the vector: std::vector<Bullet>
If the vector is not supposed to own the Bullet
s then the duty to delete them lies with whatever object is actually owning them, but even then there needs to be some effort made to assure deleted pointers do not remain in the vector.
add a comment |
You need to delete
the objects you've created with new
(unless you surrender the pointer to a std::unique_ptr
or std::shared_ptr
). Consider letting the vector be the owner of the objects instead.
std::vector<Bullet> bulletVector;
// in C++17, emplace_back returns a ref to the new Bullet:
Bullet& aNewBullet = bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
// pre C++17:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
Bullet& aNewBullet = bulletVector.back();
aNewBullet.assignTexture(btext);
When you now erase()
an object from the vector, it will be destructed automatically.
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
No, I suggested that OP should consider declaring itstd::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.
– Ted Lyngmo
Nov 15 '18 at 14:36
add a comment |
First, it is highly likely you problem is solvable by not using manual dynamic allocation in the first place. There are reasons where you can use dynamic allocation (a polymorphic storage, for example), but even then you should steer toward smart pointers rather than manual allocations.
Ditch the pointers
To do this with a regular vector of concrete objects (not pointers), you would simply
std::vector<Bullet> bulletVector;
Additions could be done with something like this:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
bulletVector.back().assignTexture(btext);
Removing all elements based on duration reaching zero would simply use the remove/erase idiom like this:
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b.getDuration() == 0; ),
bulletVector.end());
Keep in mind, while this is easily the preferred method for storing these things, it will require changes in the rest of your code. Everywhere you currently do this:
bulletVector[i]->doSomething();
will become
bulletVector[i].doSomething();
More Intelligent Pointers
If you must use dynamic allocation, don't use manually managed pointers. They're a recipe for memory leaks and ownership responsibility, and if you think it can't happen to you, you're being naive. Rather, use smart pointers. The two main smart pointer templates are std::unique_ptr
and std::shared_ptr
. There is also std::weak_ptr
, which deserve an honorable mention, as it comes in very handy in certain situations (not yours, that I can tell).
std::vector<std::shared_ptr<Bullet>> bulletVector;
Hence additions can be done like this (assuming this is done with polymorphism in mind and there may be more than one bullet type, in this case MagicBullet
and SilverBullet
, both derived from Bullet
):
std::shared_ptr<Bullet> bullet = std::make_shared<MagicBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
bullet = std::make_shared<SilverBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
or just store regular bullets:
bullet = std::make_shared<Bullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
The removal algorithm is identical, only the condition predicate function changes (and not by much)
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b->getDuration() == 0; ),
bulletVector.end());
The nicest part of this is the remainder of your code will likely require little to no changes whatsoever. But I stress, that's the only real benefit (apart form the obvious, namely not having to manage the memory yourself any longer).
Given the choice between the two methods (vector of concrete objects vs vector of smart pointers) choose carefully. If the former works, use it. If it doesn't, either think about how it could work, or use the latter.
But above all, stop managing memory manually.
Personally I would want to recommendstd::unique_ptr
overstd::shared_ptr
asstd::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).
– Galik
Nov 15 '18 at 16:25
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
add a comment |
Of course, you must deleting Bullets by yourself by delete. But your deletion cycle is not correct.
To delete values from vector with some condition, use something like this:
auto condFunc = (const Bullet* x)
bool rez = (x->getDuration() == 0);
if(rez)
delete x;
return rez;
;
bulletVector.erase(std::remove_if(bulletVector.begin(), bulletVector.end(), condFunc), bulletVector.end());
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53320959%2fmemory-leaks-in-a-pointer-vector%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
In the first code example you are not deleting any Bullet
object. Erasing vector
does only remove the pointers, not delete the pointed to object.
Your second example does properly delete Bullet
s (not all of them given the conditionals and loop setup), but only if you do the necessary deletion at all points where the vector is modified and manually assure that a pointer is never deleted twice (e.g. because it is present in two vectors). This is not how containers are supposed to be used.
If you really want to store pointers and have the vector own them, then you should use std::vector<std::unique_ptr<Bullet>>
which will properly delete the Bullet
objects when the vector is erased. However the vector will become non-copyable (only movable).
If however the vector is supposed own the Bullet
s anyway, then you can simply store them directly in the vector: std::vector<Bullet>
If the vector is not supposed to own the Bullet
s then the duty to delete them lies with whatever object is actually owning them, but even then there needs to be some effort made to assure deleted pointers do not remain in the vector.
add a comment |
In the first code example you are not deleting any Bullet
object. Erasing vector
does only remove the pointers, not delete the pointed to object.
Your second example does properly delete Bullet
s (not all of them given the conditionals and loop setup), but only if you do the necessary deletion at all points where the vector is modified and manually assure that a pointer is never deleted twice (e.g. because it is present in two vectors). This is not how containers are supposed to be used.
If you really want to store pointers and have the vector own them, then you should use std::vector<std::unique_ptr<Bullet>>
which will properly delete the Bullet
objects when the vector is erased. However the vector will become non-copyable (only movable).
If however the vector is supposed own the Bullet
s anyway, then you can simply store them directly in the vector: std::vector<Bullet>
If the vector is not supposed to own the Bullet
s then the duty to delete them lies with whatever object is actually owning them, but even then there needs to be some effort made to assure deleted pointers do not remain in the vector.
add a comment |
In the first code example you are not deleting any Bullet
object. Erasing vector
does only remove the pointers, not delete the pointed to object.
Your second example does properly delete Bullet
s (not all of them given the conditionals and loop setup), but only if you do the necessary deletion at all points where the vector is modified and manually assure that a pointer is never deleted twice (e.g. because it is present in two vectors). This is not how containers are supposed to be used.
If you really want to store pointers and have the vector own them, then you should use std::vector<std::unique_ptr<Bullet>>
which will properly delete the Bullet
objects when the vector is erased. However the vector will become non-copyable (only movable).
If however the vector is supposed own the Bullet
s anyway, then you can simply store them directly in the vector: std::vector<Bullet>
If the vector is not supposed to own the Bullet
s then the duty to delete them lies with whatever object is actually owning them, but even then there needs to be some effort made to assure deleted pointers do not remain in the vector.
In the first code example you are not deleting any Bullet
object. Erasing vector
does only remove the pointers, not delete the pointed to object.
Your second example does properly delete Bullet
s (not all of them given the conditionals and loop setup), but only if you do the necessary deletion at all points where the vector is modified and manually assure that a pointer is never deleted twice (e.g. because it is present in two vectors). This is not how containers are supposed to be used.
If you really want to store pointers and have the vector own them, then you should use std::vector<std::unique_ptr<Bullet>>
which will properly delete the Bullet
objects when the vector is erased. However the vector will become non-copyable (only movable).
If however the vector is supposed own the Bullet
s anyway, then you can simply store them directly in the vector: std::vector<Bullet>
If the vector is not supposed to own the Bullet
s then the duty to delete them lies with whatever object is actually owning them, but even then there needs to be some effort made to assure deleted pointers do not remain in the vector.
edited Nov 15 '18 at 14:06
answered Nov 15 '18 at 13:59
user10605163user10605163
2,868624
2,868624
add a comment |
add a comment |
You need to delete
the objects you've created with new
(unless you surrender the pointer to a std::unique_ptr
or std::shared_ptr
). Consider letting the vector be the owner of the objects instead.
std::vector<Bullet> bulletVector;
// in C++17, emplace_back returns a ref to the new Bullet:
Bullet& aNewBullet = bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
// pre C++17:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
Bullet& aNewBullet = bulletVector.back();
aNewBullet.assignTexture(btext);
When you now erase()
an object from the vector, it will be destructed automatically.
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
No, I suggested that OP should consider declaring itstd::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.
– Ted Lyngmo
Nov 15 '18 at 14:36
add a comment |
You need to delete
the objects you've created with new
(unless you surrender the pointer to a std::unique_ptr
or std::shared_ptr
). Consider letting the vector be the owner of the objects instead.
std::vector<Bullet> bulletVector;
// in C++17, emplace_back returns a ref to the new Bullet:
Bullet& aNewBullet = bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
// pre C++17:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
Bullet& aNewBullet = bulletVector.back();
aNewBullet.assignTexture(btext);
When you now erase()
an object from the vector, it will be destructed automatically.
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
No, I suggested that OP should consider declaring itstd::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.
– Ted Lyngmo
Nov 15 '18 at 14:36
add a comment |
You need to delete
the objects you've created with new
(unless you surrender the pointer to a std::unique_ptr
or std::shared_ptr
). Consider letting the vector be the owner of the objects instead.
std::vector<Bullet> bulletVector;
// in C++17, emplace_back returns a ref to the new Bullet:
Bullet& aNewBullet = bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
// pre C++17:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
Bullet& aNewBullet = bulletVector.back();
aNewBullet.assignTexture(btext);
When you now erase()
an object from the vector, it will be destructed automatically.
You need to delete
the objects you've created with new
(unless you surrender the pointer to a std::unique_ptr
or std::shared_ptr
). Consider letting the vector be the owner of the objects instead.
std::vector<Bullet> bulletVector;
// in C++17, emplace_back returns a ref to the new Bullet:
Bullet& aNewBullet = bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
// pre C++17:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
Bullet& aNewBullet = bulletVector.back();
aNewBullet.assignTexture(btext);
When you now erase()
an object from the vector, it will be destructed automatically.
answered Nov 15 '18 at 14:08
Ted LyngmoTed Lyngmo
3,1072518
3,1072518
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
No, I suggested that OP should consider declaring itstd::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.
– Ted Lyngmo
Nov 15 '18 at 14:36
add a comment |
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
No, I suggested that OP should consider declaring itstd::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.
– Ted Lyngmo
Nov 15 '18 at 14:36
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
the vector is declared as vector<Bullet*> bulletVector; in the class, is removing the asterisk correct?
– martincito
Nov 15 '18 at 14:27
No, I suggested that OP should consider declaring it
std::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.– Ted Lyngmo
Nov 15 '18 at 14:36
No, I suggested that OP should consider declaring it
std::vector<Bullet> bulletVector;
instead - if it doesn't mess up the rest of the design of course.– Ted Lyngmo
Nov 15 '18 at 14:36
add a comment |
First, it is highly likely you problem is solvable by not using manual dynamic allocation in the first place. There are reasons where you can use dynamic allocation (a polymorphic storage, for example), but even then you should steer toward smart pointers rather than manual allocations.
Ditch the pointers
To do this with a regular vector of concrete objects (not pointers), you would simply
std::vector<Bullet> bulletVector;
Additions could be done with something like this:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
bulletVector.back().assignTexture(btext);
Removing all elements based on duration reaching zero would simply use the remove/erase idiom like this:
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b.getDuration() == 0; ),
bulletVector.end());
Keep in mind, while this is easily the preferred method for storing these things, it will require changes in the rest of your code. Everywhere you currently do this:
bulletVector[i]->doSomething();
will become
bulletVector[i].doSomething();
More Intelligent Pointers
If you must use dynamic allocation, don't use manually managed pointers. They're a recipe for memory leaks and ownership responsibility, and if you think it can't happen to you, you're being naive. Rather, use smart pointers. The two main smart pointer templates are std::unique_ptr
and std::shared_ptr
. There is also std::weak_ptr
, which deserve an honorable mention, as it comes in very handy in certain situations (not yours, that I can tell).
std::vector<std::shared_ptr<Bullet>> bulletVector;
Hence additions can be done like this (assuming this is done with polymorphism in mind and there may be more than one bullet type, in this case MagicBullet
and SilverBullet
, both derived from Bullet
):
std::shared_ptr<Bullet> bullet = std::make_shared<MagicBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
bullet = std::make_shared<SilverBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
or just store regular bullets:
bullet = std::make_shared<Bullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
The removal algorithm is identical, only the condition predicate function changes (and not by much)
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b->getDuration() == 0; ),
bulletVector.end());
The nicest part of this is the remainder of your code will likely require little to no changes whatsoever. But I stress, that's the only real benefit (apart form the obvious, namely not having to manage the memory yourself any longer).
Given the choice between the two methods (vector of concrete objects vs vector of smart pointers) choose carefully. If the former works, use it. If it doesn't, either think about how it could work, or use the latter.
But above all, stop managing memory manually.
Personally I would want to recommendstd::unique_ptr
overstd::shared_ptr
asstd::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).
– Galik
Nov 15 '18 at 16:25
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
add a comment |
First, it is highly likely you problem is solvable by not using manual dynamic allocation in the first place. There are reasons where you can use dynamic allocation (a polymorphic storage, for example), but even then you should steer toward smart pointers rather than manual allocations.
Ditch the pointers
To do this with a regular vector of concrete objects (not pointers), you would simply
std::vector<Bullet> bulletVector;
Additions could be done with something like this:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
bulletVector.back().assignTexture(btext);
Removing all elements based on duration reaching zero would simply use the remove/erase idiom like this:
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b.getDuration() == 0; ),
bulletVector.end());
Keep in mind, while this is easily the preferred method for storing these things, it will require changes in the rest of your code. Everywhere you currently do this:
bulletVector[i]->doSomething();
will become
bulletVector[i].doSomething();
More Intelligent Pointers
If you must use dynamic allocation, don't use manually managed pointers. They're a recipe for memory leaks and ownership responsibility, and if you think it can't happen to you, you're being naive. Rather, use smart pointers. The two main smart pointer templates are std::unique_ptr
and std::shared_ptr
. There is also std::weak_ptr
, which deserve an honorable mention, as it comes in very handy in certain situations (not yours, that I can tell).
std::vector<std::shared_ptr<Bullet>> bulletVector;
Hence additions can be done like this (assuming this is done with polymorphism in mind and there may be more than one bullet type, in this case MagicBullet
and SilverBullet
, both derived from Bullet
):
std::shared_ptr<Bullet> bullet = std::make_shared<MagicBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
bullet = std::make_shared<SilverBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
or just store regular bullets:
bullet = std::make_shared<Bullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
The removal algorithm is identical, only the condition predicate function changes (and not by much)
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b->getDuration() == 0; ),
bulletVector.end());
The nicest part of this is the remainder of your code will likely require little to no changes whatsoever. But I stress, that's the only real benefit (apart form the obvious, namely not having to manage the memory yourself any longer).
Given the choice between the two methods (vector of concrete objects vs vector of smart pointers) choose carefully. If the former works, use it. If it doesn't, either think about how it could work, or use the latter.
But above all, stop managing memory manually.
Personally I would want to recommendstd::unique_ptr
overstd::shared_ptr
asstd::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).
– Galik
Nov 15 '18 at 16:25
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
add a comment |
First, it is highly likely you problem is solvable by not using manual dynamic allocation in the first place. There are reasons where you can use dynamic allocation (a polymorphic storage, for example), but even then you should steer toward smart pointers rather than manual allocations.
Ditch the pointers
To do this with a regular vector of concrete objects (not pointers), you would simply
std::vector<Bullet> bulletVector;
Additions could be done with something like this:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
bulletVector.back().assignTexture(btext);
Removing all elements based on duration reaching zero would simply use the remove/erase idiom like this:
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b.getDuration() == 0; ),
bulletVector.end());
Keep in mind, while this is easily the preferred method for storing these things, it will require changes in the rest of your code. Everywhere you currently do this:
bulletVector[i]->doSomething();
will become
bulletVector[i].doSomething();
More Intelligent Pointers
If you must use dynamic allocation, don't use manually managed pointers. They're a recipe for memory leaks and ownership responsibility, and if you think it can't happen to you, you're being naive. Rather, use smart pointers. The two main smart pointer templates are std::unique_ptr
and std::shared_ptr
. There is also std::weak_ptr
, which deserve an honorable mention, as it comes in very handy in certain situations (not yours, that I can tell).
std::vector<std::shared_ptr<Bullet>> bulletVector;
Hence additions can be done like this (assuming this is done with polymorphism in mind and there may be more than one bullet type, in this case MagicBullet
and SilverBullet
, both derived from Bullet
):
std::shared_ptr<Bullet> bullet = std::make_shared<MagicBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
bullet = std::make_shared<SilverBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
or just store regular bullets:
bullet = std::make_shared<Bullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
The removal algorithm is identical, only the condition predicate function changes (and not by much)
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b->getDuration() == 0; ),
bulletVector.end());
The nicest part of this is the remainder of your code will likely require little to no changes whatsoever. But I stress, that's the only real benefit (apart form the obvious, namely not having to manage the memory yourself any longer).
Given the choice between the two methods (vector of concrete objects vs vector of smart pointers) choose carefully. If the former works, use it. If it doesn't, either think about how it could work, or use the latter.
But above all, stop managing memory manually.
First, it is highly likely you problem is solvable by not using manual dynamic allocation in the first place. There are reasons where you can use dynamic allocation (a polymorphic storage, for example), but even then you should steer toward smart pointers rather than manual allocations.
Ditch the pointers
To do this with a regular vector of concrete objects (not pointers), you would simply
std::vector<Bullet> bulletVector;
Additions could be done with something like this:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
bulletVector.back().assignTexture(btext);
Removing all elements based on duration reaching zero would simply use the remove/erase idiom like this:
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b.getDuration() == 0; ),
bulletVector.end());
Keep in mind, while this is easily the preferred method for storing these things, it will require changes in the rest of your code. Everywhere you currently do this:
bulletVector[i]->doSomething();
will become
bulletVector[i].doSomething();
More Intelligent Pointers
If you must use dynamic allocation, don't use manually managed pointers. They're a recipe for memory leaks and ownership responsibility, and if you think it can't happen to you, you're being naive. Rather, use smart pointers. The two main smart pointer templates are std::unique_ptr
and std::shared_ptr
. There is also std::weak_ptr
, which deserve an honorable mention, as it comes in very handy in certain situations (not yours, that I can tell).
std::vector<std::shared_ptr<Bullet>> bulletVector;
Hence additions can be done like this (assuming this is done with polymorphism in mind and there may be more than one bullet type, in this case MagicBullet
and SilverBullet
, both derived from Bullet
):
std::shared_ptr<Bullet> bullet = std::make_shared<MagicBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
bullet = std::make_shared<SilverBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
or just store regular bullets:
bullet = std::make_shared<Bullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
The removal algorithm is identical, only the condition predicate function changes (and not by much)
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
(auto const& b) return b->getDuration() == 0; ),
bulletVector.end());
The nicest part of this is the remainder of your code will likely require little to no changes whatsoever. But I stress, that's the only real benefit (apart form the obvious, namely not having to manage the memory yourself any longer).
Given the choice between the two methods (vector of concrete objects vs vector of smart pointers) choose carefully. If the former works, use it. If it doesn't, either think about how it could work, or use the latter.
But above all, stop managing memory manually.
answered Nov 15 '18 at 14:37
WhozCraigWhozCraig
51.5k958108
51.5k958108
Personally I would want to recommendstd::unique_ptr
overstd::shared_ptr
asstd::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).
– Galik
Nov 15 '18 at 16:25
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
add a comment |
Personally I would want to recommendstd::unique_ptr
overstd::shared_ptr
asstd::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).
– Galik
Nov 15 '18 at 16:25
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
Personally I would want to recommend
std::unique_ptr
over std::shared_ptr
as std::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).– Galik
Nov 15 '18 at 16:25
Personally I would want to recommend
std::unique_ptr
over std::shared_ptr
as std::shared_ptr
s come with their own set of problems and should only be used when actual shared ownership is required (two or more objects need to reference the same object and it is impossible to know which will die last).– Galik
Nov 15 '18 at 16:25
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
@Galik Certainly the appropriate use case should use the appropriate pointer type. There is zero evidence in the OP's code that the instances will be unique, and shared will work in both cases. If they indeed are unique, then the only reason to use a smart pointer at all (as opposed to concrete objects) is for polymorphic reasons (which there is likewise, zero evidence is required, but is an important unknown). Regardless, the concept is the same.
– WhozCraig
Nov 15 '18 at 17:00
add a comment |
Of course, you must deleting Bullets by yourself by delete. But your deletion cycle is not correct.
To delete values from vector with some condition, use something like this:
auto condFunc = (const Bullet* x)
bool rez = (x->getDuration() == 0);
if(rez)
delete x;
return rez;
;
bulletVector.erase(std::remove_if(bulletVector.begin(), bulletVector.end(), condFunc), bulletVector.end());
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
add a comment |
Of course, you must deleting Bullets by yourself by delete. But your deletion cycle is not correct.
To delete values from vector with some condition, use something like this:
auto condFunc = (const Bullet* x)
bool rez = (x->getDuration() == 0);
if(rez)
delete x;
return rez;
;
bulletVector.erase(std::remove_if(bulletVector.begin(), bulletVector.end(), condFunc), bulletVector.end());
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
add a comment |
Of course, you must deleting Bullets by yourself by delete. But your deletion cycle is not correct.
To delete values from vector with some condition, use something like this:
auto condFunc = (const Bullet* x)
bool rez = (x->getDuration() == 0);
if(rez)
delete x;
return rez;
;
bulletVector.erase(std::remove_if(bulletVector.begin(), bulletVector.end(), condFunc), bulletVector.end());
Of course, you must deleting Bullets by yourself by delete. But your deletion cycle is not correct.
To delete values from vector with some condition, use something like this:
auto condFunc = (const Bullet* x)
bool rez = (x->getDuration() == 0);
if(rez)
delete x;
return rez;
;
bulletVector.erase(std::remove_if(bulletVector.begin(), bulletVector.end(), condFunc), bulletVector.end());
edited Nov 15 '18 at 14:23
answered Nov 15 '18 at 13:56
snake_stylesnake_style
1,170410
1,170410
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
add a comment |
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
Your example code doesn't delete the pointees either though, despite being a nicer way to erase them from the vector.
– Pete Kirkham
Nov 15 '18 at 14:13
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
@PeteKirkham this example was "To delete values from vector", not to free memory
– snake_style
Nov 15 '18 at 14:25
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
In that case it doesn't answer the question, which was about both removing them from the vector and deleting them from the heap. In C++ there is no such thing as 'deleting values from a vector' as 'delete' has a very specific meaning.
– Pete Kirkham
Nov 15 '18 at 14:34
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53320959%2fmemory-leaks-in-a-pointer-vector%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
Do you need to use
new
/delete
? Why not just usestd::vector<Bullet>
?– CoryKramer
Nov 15 '18 at 13:52
Collections of raw pointers are just not a good idea. Either the collection owns the objects pointed to or it doesn't. If it does own them, why use pointers at all? If it doesn't own them, managing the lifetime of the objects becomes very complicated.
– David Schwartz
Nov 15 '18 at 14:42