I'm creating an object via new, then later adding the pointer to an std::list once the object is set up.
What is the correct way of deleting a pointer and erasing the data from the list without causing memory leaks?
Instead of manual loop to search the element, I would rather use std::find_if
auto it = std::find_if(lst.begin(),
lst.end(),
[&val](datalist const &d) { return d.index == val; });
if ( it != lst.end() )
{
delete *it;
lst.erase(it);
}
That is not to say that you're doing it incorrectly.
However, your code will improve if you consider using some form of smart points, such as std::unique_ptr, std::shared_ptr, or boost's smart pointers, then you don't have to manage memory yourself.
If you change your std::list to hold datalist instances instead of datalist* pointers, then you don't have to delete the datalist instances manually anymore. When you remove an element from a std::list (or any other STL container, for that matter), the element's data is freed automatically for you. If the element is a class/struct with a destructor defined, the destructor will be called.
Try this:
std::list<datalist> m_DataList;
.
datalist AR; // <-- local variable on the stack, freed when out of scope
AR.index = ...;
AR.number = ...;
mylist.push_back(AR); // <-- pushes a copy-constructed instance of the variable
.
std::list<datalist>::iterator Iter1 = m_DataList.begin();
while(Iter1 != m_DataList.end())
{
if (Iter1->index == m_SomeVar)
{
m_DataList.erase(Iter1); // <-- copied datalist instance is freed automatically
break;
}
++Iter1;
}
Related
I'm getting memory leak issues in one of my applications that I'm going through and trying to fix. One of my suspected problem points is where I parse lines from a file into commands using BNFC:
void LineStreamScriptProvider::populateQueue()
{
if(shouldPopulate())
{
TasScript::ShowAbsyn shower;
std::string line;
while(queueSize() < 30 && !stream.eof())
{
std::getline(stream, line);
const char* lineCStr = line.c_str();
TasScript::Program* lineCmds = TasScript::pProgram(lineCStr);
TasScript::P* asLeaf = static_cast<TasScript::P*>(lineCmds);
TasScript::ListCommand* cList = asLeaf->listcommand_;
for_each(cList->begin(), cList->end(), [this, shower](TasScript::Command* cmd) {
// log_to_sd_out("Parsed command %s\n", shower->show(cmd));
std::shared_ptr<TasScript::Command> cmdShared(cmd);
pushToQueue(cmdShared);
});
}
if(stream.eof())
{
afterEOF();
}
}
}
For reference:
class P : public Program
{
public:
ListCommand *listcommand_;
// ...
class ListCommand : public Visitable, public std::vector<Command*>
{
// ...
BNFC constructs these with new and then returns the pointers. Is it safe to delete lineCmds without deleting the value held by cmdShared?
Sorry, I wasn't aware of BNFC and that it creates raw pointers for you.
Is it safe to delete lineCmds without deleting the value held by
cmdShared?
If you are creating a shared pointer from a raw pointer the shared pointer takes ownership of that resource. The shared pointer will maintain a reference count for that resource until it drops to zero, i.e. when all shared pointers for that resource go out of scope, at which point it will try to destroy the resource.
Here you are creating a shared pointer and passing it to a queue:
std::shared_ptr<TasScript::Command> cmdShared(cmd);
pushToQueue(cmdShared);
The shared pointer will take care of the memory management for you. So there is no need to explicitly call delete on the vector of commands. Once all shared pointers of type std::shared_ptr<TasScript::Command> are destroyed the resource is also destroyed.
So no, it is not safe to delete a vector of pointers in this case.
Another simpler solution is to take a copy of the TasScript::Command:
TasScript::Command cmdCopy(*cmd);
Then change pushToQueue() to accept by const TasScript::Command&, not by shared pointer. Then you don't have to worry about the pointer being destroyed since you have a copy of the value.
It looks like in your while loop you are leaking memory. Don't you have to delete lineCmds and cList?
Well I am creating a vector like this
vector<Member*> emp;
Then I am creating heap objects of the member class like this
Member* memObj = new Member();
Then using push_back like this
emp.push_back(memObj);
Well after using all my functions do I have to clear the memory by iterating like this ?
for( vector<Member*>::iterator iter = emp.begin();
iter != emp.end(); )
{
Member* mem = *iter;
iter = emp.erase (iter);
delete mem;
//iter++;
}
Is there any effective way other than iterating through each value? clear function calls the destructor only and it clears the values but does not free the memory..I wish to achieve polymorphism here...I am new in C++ ....please help..Thanks in advance.. :) I am not using C++11
If you are able to use a C++11 compiler, you can use one of the smart pointers.
std::unique_ptr
std::vector<std::unique_ptr<Member>> emp;
or
std::shared_ptr
std::vector<std::shared_ptr<Member>> emp;
EDIT
If you are not able to use a C++11 compiler, VS 2005 is definitely too old to support C++11, you will have to delete the objects manually, like you have shown.
However, I would add a helper class to help with deleteing the Member objects.
struct MemberDeleteHelper
{
MemberDeleteHelper(std::vector<Member*> emp) : emp_(emp);
~MemberDeleteHelper()
{
for( vector<Member*>::iterator iter = emp.begin();
iter != emp.end(); ++iter )
{
delete *iter;
}
}
std::vector<Member*>& emp_;
};
and use it as:
vector<Member*> emp;
MemberDeleteHelper deleteHelper(emp);
With this in place, the elements of emp will be deleted no matter how you return from the function. If an exception gets thrown from a nested function call, the stack will be unrolled and the elements of emp will still be deleted.
EDIT 2
Do not use auto_ptr objects in std::vector. The pitfalls of using auto_ptr in STL containers are discussed at http://www.devx.com/tips/Tip/13606 (Thanks are due to #pstrjds for the link).
Unless your intent is to added instances of types derived from Member to the vector, there's no need for vector<Member*>, just use vector<Member>.
If you actually need dynamic allocation, use vector<unique_ptr<Member>>. The smart pointer will automatically delete the instances when you clear() the vector. If this is the case, don't forget that Member needs a virtual destructor.
Similar options for pre-C++11 compilers are std::vector<std::tr1::shared_ptr<Member>> or boost::ptr_vector<Member>.
Finally, your current code has a bug. vector::erase returns a pointer to the next element, so by manually incrementing the iterator within the loop, you're skipping every other element. And I don't understand why you're going through the trouble of storing the pointer in a temporary variable. Your loop should be
for( vector<Member*>::iterator iter = emp.begin(); iter != emp.end(); )
{
delete *iter;
iter = emp.erase(iter);
}
or just delete all the elements first and then clear the vector
for( vector<Member*>::iterator iter = emp.begin(); iter != emp.end(); ++iter)
{
delete *iter;
}
emp.clear();
I have a created a class 'Route' which stores a linked list. Objects of the 'Route' class are stored in vectors (and sometimes deleted).
Without a copy constructor/destructor/etc. the program works fine, but I want to avoid memory leaks, so I need a copy constructor/destructor etc. Since creating these, vector 'erase' seems to delete the wrong elements from the vector (ie, the last element, not the nth element). Sometimes elements get erased from vectors even though none should be deleted. Is there something wrong with my constructor/destructor/copy constructor? (Every time a Route object is copied, to be put on to a vector, an entirely new version of the linked list is created, using new memory - using the 'copyLinkedList' function).
`Route::Route(int destnAddr, MovePtr routeToDestn) :
destinationAddress(destnAddr){
firstMove = copyLinkedList(routeToDestn);
}
Route::Route(const Route& _route){
destinationAddress = _route.destinationAddress;
firstMove = copyLinkedList(_route.firstMove);
}
Route& Route::operator=(const Route& _route){
Route newRoute(_route);
return newRoute;
}
Route::~Route(){
MovePtr toDelete = firstMove;
while(firstMove != NULL){
firstMove = firstMove->next_move;
delete toDelete;
toDelete = firstMove;
}
}
MovePtr Route::copyLinkedList(MovePtr listHead) {
MovePtr newListHead = NULL;
if (listHead == NULL){
return newListHead;
}
newListHead = new Move;
newListHead->router_address = listHead->router_address;
newListHead->next_move = copyLinkedList(listHead->next_move);
return newListHead;
}`
What you're doing in operator= makes no sense whatsoever. You should assign the state of the parameter to the current object. Instead, you create a new object and return a dangling reference to it.
Try to google for "assignment operator" or "special member functions" or "rule of three" for details.
For some reason this isn't working for me. It gives me the vector iterator out of range error.
directory_entry TDE("Path");
vector <directory_entry> Temp;
Temp.push_back(TDE);
User_Data->DPath.insert(User_Data->DPath.begin(), Temp.begin(), Temp.end());
But, this works,
vector <directory_entry> DPath;
directory_entry TDE("Path");
vector <directory_entry> Temp;
Temp.push_back(TDE);
DPath.insert(DPath.begin(), Temp.begin(), Temp.end());
I don't think there is anything wrong with User_Data->DPath because I can push/pop and access elements in it. But for some reason I can't seam to be able to use insert on it without getting out of range errors.
Does anyone know why this might be?
edit: A popup emerges, debug assertion failed. It gives me a line in the vector header file, 1111, and a message "Expression: vector iterator out of range". If I make sure that there is at least one element in User_Data->DPath, and then start at .begin+1, I get "Expression: vector iterator+offset out of range" and it gives me line 157 of the vector header file.
edit: You are all probably right. The g_new0 function does the memory allocation http://developer.gnome.org/glib/2.32/glib-Memory-Allocation.html#g-new0
struct_type : the type of the elements to allocate. n_structs : the
number of elements to allocate. Returns : a pointer to the allocated
memory, cast to a pointer to struct_type.
typedef struct {
vector <directory_entry> DPath;
}State;
static gboolian select_dir (ClutterActor *actor, ClutterEvent *event, g_pointer data){
State *User_Data = (State*)data;
directory_entry Temp(Path);
User_Data->DPath.push_back(Temp);
...
return TRUE;
}
int main( argc, char*argv[]){
State *data = g_new0 (State, 1);
...
g_signal_connect(Cluter_Actor, "button-event", G_CALLBACK(select_dir), data)
...
clutter_main();
g_free(data);
return 0;
}
g_new0 is not a drop-in replacement for new
new does two things: allocates memory for an object, and calls the object's constructor. g_new0 only does the first, allocating memory. You need to call the object's constructor explicitly if you want to use g_new0. This is done using "placement new":
State *data = g_new0 (State, 1);
new (data) State; // placement new - calls the constructor
The reason calling State's constructor is important is that it in turn calls the constructor of the vector<directory_entry> member of State, and this is what initializes the vector. Without initializing the vector properly, you cannot use it.
Note that since you are calling the constructor explicitly, you will also need to call the destructor explicitly before freeing the memory:
data->~State(); // call destructor
g_free(data); // free the memory
Is there a reason you are using g_new0 instead of just new?
State *data = new State;
... // use data
delete data;
This code is causing a memory leak for me, and I'm not sure why.
[EDIT] Included code from here into question:
#include "src/base.cpp"
typedef std::map<std::string, AlObj*, std::less<std::string>,
gc_allocator<std::pair<const std::string, AlObj*> > > KWARG_TYPE;
AlInt::AlInt(int val) {
this->value = val;
this->setup();
}
// attrs is of type KWARG_TYPE
void AlInt::setup() {
this->attrs["__add__"] = new AddInts();
this->attrs["__sub__"] = new SubtractInts();
this->attrs["__mul__"] = new MultiplyInts();
this->attrs["__div__"] = new DivideInts();
this->attrs["__pow__"] = new PowerInts();
this->attrs["__str__"] = new PrintInt();
}
int main() {
while (true) {
AlObj* a = new AlInt(3);
}
}
AlInt inherits from AlObj, which in turn inherits from gc. When I comment out the contents of setup() then I don't have a memory leak, this leads me to believe the issue is with the map not cleaning up, however I'm using the gc allocator, so I'm not sure where to look next. Thoughts?
The 'gc allocator' is allocating and looking after objects of this type:
std::pair<const std::string, AlObj*>
Just because this object has a pointer in it does not mean it the allocator will call delete on it.
If you want the object created in setUp() to be GC then you need to allocate them via the GC. Or learn to use boost:ptr_map or shared_ptr.
A map destroys (not deletes) the object it owns. In this case it owns the pointer not what the pointer points at. So when the map is destroyed it deallocates everything associated with the map and the object it owns (for pointers this means it does nothing).
If you have a map (or other container) that contains pointers. You must manually delete the pointers otherwise there will be a memory leak. Alternatively you can use boost::ptr_map or a map that contains a share_ptr
The allocator is deleting your pairs. But deleting a pair doesn't delete members of the pair that happen to be pointers.