So I've completely edited my question.
I have a map called mTextMap which contains:
typedef std::map<const std::string, Text*> TextMap;
TextMap mTextMap;
And I have the following methods:
void Foo::setUpGame()
{
Text text(1,2,3,4); //create a Text object
mTextMap["MainText"] = &text; //save it in the map!
}
Text& Foo::getText(const std::string name)
{
auto i= mTextMap.find(name);
return *(i->second); //Gets a reference to the Text that is inside the map
}
Now if I use this way:
Foo foo;
foo.setUpGame();
Text& myText = foo.getText("MainText"); // Why is this corrupted?
The object myText is completely corrupted!!
Why is this happening?
The general problem seems to be, that you think that this line:
mTextMap["MainText"] = &text;
stores the text object in the map. IT DOESN'T! It stores a pointer to the object in the map and the text object itself will - as you said yourself - automatically be destructed at the end of the function. So now your pointer points to a non-existing object, which leads to the observed errors.
There are various solutions to your problem, depending on what exactly, you try to achieve and what you are going to do with your class.
One possibility is to use a map of Text objects (instead of pointers):
typedef std::map<const std::string, Text> TextMap;
void Foo::setUpGame()
{
Text text(1, 2, 3, 4); //create a Text object
mTextMap["MainText"] = text; //copy it into the map!
}
or
void Foo::setUpGame()
{
mTextMap.emplace("MainText", Text(1, 2, 3, 4)); //Doesn't require Text to be default constructable
}
Another possibility is to create the text objects on the heap and use smart pointers (e.g. unique_ptr)
typedef std::map<const std::string, std::unique_ptr<Text>> TextMap;
void Foo::setUpGame()
{
mTextMap["MainText"] = std::make_unique<Text>(1,2,3,4); //create object on the heap an store a pointer to it in the map
}
The std::unique_ptr will automatically destroy the text object, as soon as the map gets destroyed.
If you really need to have a map of raw pointers for some reason, you can use "new" as explained by David, but don't forget to delete them when you don't use them anymore - c++ doesn't have a garbage collector (like e.g. java) that would take care of this automatically.
The "text" object is going out of scope as soon as setUpGame completes. At this point, the heap memory is freed up to be overwritten by any new use of the heap. It is essentially a temporary scratchpad of items that only exists within the scope of a function (or within explicit scope operators inside a function).
David G's advice is sound: read more about the difference between stack and heap memory, and also consider the advice to use smart pointers. However, if you want a cheap, dirty fix to your immediate problem, you can try this:
void Foo::setUpGame()
{
static Text text(1,2,3,4); // Note use of "static" keyword
mTextMap["MainText"] = &text; //save it in the map!
}
Whilst I do not advocate the use of static as a shortcut to solving more fundamental architectural memory issues, you can use this as a short-term measure if you're desperate to get things working. Labeling the object as static ensures its lifetime will outlive the scope of the function. But I would not recommend it as a long-term solution to this kind of issue.
When you dynamically allocate memory for your object, it will live as long as you do not explicitly delete it from memory, it is not deleted after you exit the method it was created in, so you can put a pointer to it in a map and it will always be there (just be sure you delete the memory when removing the object from the map).
You can test this with the following simple code, where I declare a new Int in a function, return a pointer to the memory and print it in the other function that received the map (with the pointer in it). It prints correctly, which means the memory was not freed even when out of scope.
#include <iostream>
#include <map>
std::map<std::string, int*> myMap(){
int* test = new int(1);
std::map<std::string, int*> ObjMap;
ObjMap["object"] = test;
return ObjMap;
}
int main(int argc, const char * argv[]) {
// insert code here...
std::map<std::string, int*> mmap = myMap();
std::cout << *mmap["object"] << std::endl;
return 0;
}
So to answer your question, create your object dynamically like this:
Obj* obj = new obj(1,2,3,4);
And it will not be deleted when out of scope. Still, you need to delete the memory yourself unless you use Smart Pointer, like this: delete obj; (when you remove it from the map, to free the memory as it will not be freed automatically).
PS: You should read on how the Stack and Heap works and how Dynamic and Static allocation works (using the stack OR the heap). See this c++ dynamic memory allocation tutorial to have more informations.
Like MikeMB said, using Smart Pointers is easier as you will be sure you deleted the memory, and you will also be sure you never access a deleted memory. See this Stack Overflow topic for smart pointers informations: What is a smart pointer and when should I use one?
Related
I'm using a library that, in order to construct some object that I use, expects a raw pointer to an object. I'm not sure what it will do with the pointer, to make my code as safe as possible, what should I pass to this function?
Use a unique pointer - if they decide to delete the pointer, I will do a double-delete
Keep track of a raw pointer - bad because I have to remember to write delete, but it could still be a double-delete
Use auto duration and give them a pointer Give them a reference - their code will error if they call delete
Use a shared pointer - same double-delete problem as unique pointer, but now my scope won't hurt their pointer
Based on my reading, option 3 seems like what I should do - they shouldn't be calling delete on the pointer, and this format enforces that. But what if I don't know whether they now or in the future will call delete on the reference I gave them? Use a shared pointer and say "not my fault about the double delete"?
#include <memory>
#include <iostream>
class ComplexObj {
public:
ComplexObj() : m_field(0) {}
ComplexObj(int data) : m_field(data) {}
void print() { std::cout << m_field << std::endl; }
private:
int m_field;
};
class BlackBox {
public:
BlackBox(ComplexObj* data) {
m_field = *data;
// Do other things I guess...
delete data;
std::cout << "Construction complete" << std::endl;
}
void print_data() { m_field.print(); }
private:
ComplexObj m_field;
};
int main(int argc, char* argv[]) {
// Use a smart pointer
std::unique_ptr<ComplexObj> my_ptr(new ComplexObj(1));
BlackBox obj1 = BlackBox(my_ptr.get());
obj1.print_data();
my_ptr->print(); // Bad data, since BlackBox free'd
// double delete when my_ptr goes out of scope
// Manually manage the memory
ComplexObj* manual = new ComplexObj(2);
BlackBox obj2 = BlackBox(manual);
obj2.print_data();
manual->print(); // Bad data, since BlackBox free'd
delete manual; // Pair new and delete, but this is a double delete
// Edit: use auto-duration and give them a pointer
ComplexObj by_ref(3);
BlackBox obj3 = BlackBox(&by_ref); // they can't call delete on the pointer they have
obj3.print_data();
by_ref.print();
// Use a shared pointer
std::shared_ptr<ComplexObj> our_ptr(new ComplexObj(4));
BlackBox obj4 = BlackBox(our_ptr.get());
obj4.print_data();
our_ptr->print(); // Bad data, they have free'd
// double delete when our_ptr goes out of scope
return 0;
}
Other questions I read related to this topic...
unique_ptr.get() is legit at times
I should pass by reference
I think I am case 2 and should pass by reference
You cannot solve this problem with the information you have. All choices produce garbage.
You have to read the documentation of the API you are using.
Doing any of your 4 answers without knowing if they take ownership of the pointer will result problems.
Life sometimes sucks.
If you have a corrupt or hostile API, the only halfway safe thing to do is to interact with it in a separate process, carefully flush all communication, and shut down the process.
If the API isn't corrupt or hostile, you should be able to know if it is taking ownership of the pointed to object. Calling an API without knowing this is a common mistake in novice C++ programmers. Don't do it. Yes, this sucks.
If this API is at all internal and you have any control, seek to make all "owning pointer" arguments be std::unique_ptr<>s. That makes it clear in the API that you intend to own the object and delete it later.
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?
I have tried to find an answer but couldn't see anything straight forward.
How do I free the allocated memory in the next snippet code:
const char* attStr = strdup(OtherCharStr);
string str(attStr, strlen(attStr));
delete str; //???
C++ uses idiom called RIAA - Resource Acquisition Is Initialization. It means that object lifetime is driven by variable scope.
{
std::string s("foo"); // variable s declaration and string initialization
do_some_stuff(s);
// end of scope of variable s - it is destroyed here
// no need to free(s) or whatever
}
// variable s and the string doesn't exist here, no memory for it is allocated
This applies only for C++ objects that maintain its resources properly (are freeing them in the destructor). Simple pointers doesn't do it - you have to free them yourself:
const char *attStr = strdup(...);
// do something with attStr
free(attStr); // because strdup() documentation says you should free it with free()
Also notice that C++ uses new and delete rather than malloc() and free():
std::string *strPointer = new std::string(...);
// RIAA doesn't work here, because strPointer is just plain pointer,
// so this is the case when you need to use free() or delete
delete strPointer;
I recommend to read something about smart pointers which are deleting the object they point to automatically. I'm getting pretty far from the original question but this topic is important to understand how C++ works.
You need to release attStr not the c++ string that will release its resources alone.
void func()
{
const char* attStr = strdup(OtherCharStr);
string str(attStr, strlen(attStr));
free(attStr);
}//here str will release its own resources
Also you can do
string str = OtherCharStr;
an that's it. Only check what happens with OtherCharStr
What's the best way to delete an std::string from memory allocated on the heap when I'm done using it? Thanks!
std::string is just a normal class1, so the usual rules apply.
If you allocate std::string objects on the stack, as globals, as class members, ... you don't need to do anything special, when they go out of scope their destructor is called, and it takes care of freeing the memory used for the string automatically.
int MyUselessFunction()
{
std::string mystring="Just a string.";
// ...
return 42;
// no need to do anything, mystring goes out of scope and everything is cleaned up automatically
}
The only case where you have to do something is when you allocate an std::string on the heap using the new operator; in that case, as with any object allocated with new, you have to call delete to free it.
int MyUselessFunction()
{
// for some reason you feel the need to allocate that string on the heap
std::string * mystring= new std::string("Just a string.");
// ...
// deallocate it - notice that in the real world you'd use a smart pointer
delete mystring;
return 42;
}
As implied in the example, in general it's pointless to allocate a std::string on the heap, and, when you need that, still you should encapsulate such pointer in a smart pointer to avoid even risking memory leaks (in case of exceptions, multiple return paths, ...).
Actually std::string is defined as
namespace std
{
typedef std::basic_string<char> string;
};
so it's a synonym for the instantiation of the basic_string template class for characters of type char (this doesn't change anything in the answer, but on SO you must be pedantic even on newbie questions).
std::string foo("since it's on the stack, it will auto delete out of scope");
or:
std::string* foo = new std::string("allocated on the heap needs explicit destruction")
delete foo;
Use delete if it's on the heap, and nothing at all if it's on the stack.
void foo() {
string* myString = new string("heap-allocated objects are deleted on 'delete myString;'");
cout << *myString << endl;
delete myString;
}
or better yet, avoid pointers when possible and use automatic variables:
void foo() {
string myString("stack-allocated string is automatically deleted when myString goes out of scope");
cout << myString << endl;
}
just treat std::string as any basic type.
std::string *str = new std::string("whatever");
///code
delete str;
Maybe your dealing with really freeing the internal string buffer?
For performance reason, most implementation keep the internal buffer allocated, even is the string is "emptied". Additionally: small strings (smaller than sizeof(ptr)) are directly stored in the area that hold pointers. Theses bytes can never be reclaimed during the life of the string.
To free the internals: the classical trick is to use swap within a scope. This force buffer to be really freed (Works also with vector/map/ostream/stringstream etc ...):
string s; // size==0 and capacity==15 as the default proxy of the container (help perf on small string)
s = "Looooooooooooooooooooooooooooooong String"; // size==41 and capacity==47 bytes allocated
s.clear(); // size==0 BUT capacity==47 bytes STILL allocated!!
s = "Looooooooooooooooooooooooooooooong String"; // size==41 and capacity reuse 47 bytes still allocated.
s.resize(0); // size==0 BUT capacity==47 bytes STILL allocated!!
// swap with scope to force freeing string internals
{
string o;
o.swap(s);
} // size==0 AND capacity==15 (back to smallest footprint possible)
s = "12345"; // size==5 AND capacity==15 (the string is IN the container, no new alloc)
You can treat std::string like any other class. Use new for allocation, and delete once you're done with it.
With C++11, I do not recommend usage of new and delete in most cases. If you need to allocate the string on heap, use std::shared_ptr to wrap it:
std::shared_ptr<std::string> my_string = std::make_shared<std::string>(std::string("My string"));
As soon as all the copies of my_string go out of scope, the associated memory is going to be deleted automatically.
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.