Im trying to link one display to another display using c++. For instance
void funcA(){
Display greenScreen;
Display redScreen;
greenScreen.setChild(redScreen);
}
Here's the class implementation:
class display{
public:
display* child = nullptr;
void setChild(display);
}
Implementation of setChild:
void setChild(display childnode){
child = &childnode;
}
I thought this would work, but when i tried to retrieve greenScreen's child, my app crashed. Any help would be greatly appreciated!
This is passing childnode by value: a copy is made, and you're setting this->child to the address of the copy. But the copy only lives while setChild is executing, so when it returns, you're left with a dangling pointer, causing undefined behaviour (probably crashing).
You must pass the address of childnode instead:
void setChild(display *childnode){
child = childnode;
}
Related
Can somebody please explain the segfault here:
class foo
{
private:
some_class *test_;
void init_some_class(some_class*);
void use_class();
}
foo::foo()
{
//test_ = new some_class(variables, variables); //THIS WOULD WORK
}
void foo::init_some_class(some_class *tmp)
{
tmp = new some_class(variables,variables);
}
void foo::use_class()
{
test_->class_function() //THIS SEGfaults
}
I would call the funtion via init_some_class(test_); If I use new in the constructor then the test_->class_function() works fine. It only seems to segfault when I use new outside of the class constructor and try and pass the pointer through the function
When you write in init_some class() :
tmp = new some_class(variables,variables);
you are in fact storing the new pointer in the parameter that is passed by value. But this parameter is local to the function and lost as soon as the function returns.
So if you call somewhere init_some class(test_) the value of test_ is transferred to tmp, but the changed tmp remains local to the function. You therefore get a segfault beause test_ remains uninitialized.
Possible solutions:
A simple solution to the described use case could be to pass the parameter by reference:
void foo::init_some_class(some_class *& tmp) // note the &
{
tmp = new some_class(variables,variables);
}
With this definition, when calling init_some class(test_), the original test_ pointer gets modified.
Another solution could be to have the init_some_class() change directly the test_ member. You'd then no longer need a parameter.
I have been trying to fix a potentially sketchy use of void* casting in a task scheduling application for weeks now. Note that I am NOT getting a compiler error, but the scheduling program crashes after a few hours (for some unknown reason). Consider the following code snippets from the program:
In main:
CString* buffer = new CString(temp);
parameters.set("jobID", (void *) buffer);
runJob(parameters);
Also, VGridTaskParam class is as follows:
class VGridTaskParam{
map<CString, void *> p; // maps from CString to a pointer that is not known
public:
void * get(CString name){
return p[name]; // returns the map value of the name which is an unknown pointer
}
void set(CString name, void * data){
p[name] = data; // sets the mpa value given a particular key
}
};
Snippet of some work in runJob(VGridTaskParam parameters) function is:
void runJob(VGridTaskParam parameters)
{
CString JIDstr; // job ID string
//get job ID as CString
CString* pJID = (CString*)parameters.get("jobID");
JIDstr = CString(*pJID);
delete pJID; ******************************
}
Some questions: does the last delete line (marked with several asterisks) delete the memory allocation created in the main program? Is my use of void* casting warranted in this situation. Note that whenever I run a job, I spawn a new thread. Can someone suggest a potential fix to this problem? What should I look at to fix this problem?
does the last delete line (marked with several asterisks) delete the memory allocation created in the main program?
Yes.
Is my use of void* casting warranted in this situation?
No, that is superfluous. Any pointer can be cast to void* without the explicit cast.
Can someone suggest a potential fix to this problem? What should I look at to fix this problem?
I can't suggest a fix without an MCVE.
A few possible issues:
what will happen if you write twice to same key? This will cause a memory leak.
there are few possible solutions, like:
void set(CString name, void * data){
if(p[name]!=NULL)
delete p[name];
p[name] = data; // sets the mpa value given a particular key
}
Another thing: Are you running multi-threaded or single threaded? for multi-threaded you should synchronize the get and set methods to prevent pointer changes in a middle of action.
And finally, what happen if key not found? you should check the returned pointer. also remove from the set or null it after usage.
void runJob(VGridTaskParam parameters)
{
CString JIDstr; // job ID string
//get job ID as CString
CString* pJID = (CString*)parameters.get("jobID");
if(pJID){
parameters.set("jobID",NULL);
JIDstr = CString(*pJID);
delete pJID; ******************************
}
}
I see two things that looks a bit surprising to me.
1) runJob takes parameters of type VGridTaskParam by value. Maybe you want a reference instead. That can't explain the crash, though.
2) You never seem to remove anything from the map even though you delete the memory associated with the pointer. So there is a risk that you'll use the pointer value later on. Either as a dereference or as a double delete.
3) You don't implement any check for the key being present in the map.
Your delete is correct. It deletes an allocated block of memory of the size of the pointer's type at the pointer's address. So when you allocate a CString with new you will delete the exact same amount of memory.
The hang up is when you delete unallocated memory. There are several ways I could see this happening in your current code:
runJob requests an key not in the map (this will return a default initialized CString* as the newly created value.)
You call runJob on a previously deleted item in the map (this value would already be deallocated and deleting it again would be illegal.)
We can't see all your code but if there is the potential to delete these pointers elsewhere there could also be a double cleanup problem there.
You should code your map more defensively, for example:
const void* get(const CString& name) const {
return p.find(name) == p.cend() ? nullptr : p[name]; // returns the map value of the name which is an unknown pointer
}
void set(const CString& name, void* data) {
void* toOverwrite = get(name);
if(toOverwrite != nullptr) {
delete toOverwrite;
}
p[name] = data; // sets the mpa value given a particular key
}
void remove(const CString& name) {
if(p.find(name) != p.end()) {
p.erase(name);
}
}
In your function you'd need to change to testing if the return of get was a nullptr before operating on the result, and rather than delete you'd need to call remove. This keeps all modification of p local to the class, thereby guaranteeing correct maintenance of the map.
I am trying to create a tree structure using some handler functions that are called while reading a stream. I think the problem is that my variables are created in the function's scope and disappear when the function ends, leaving pointers that point to nothing.
I am not sure what approach to take to keep the objects in memory, whilst still allowing the tree to be scalable.
I have made a simplified version of the code: it compiles and runs but the parent-child relationships of the 'Segment' objects are all wrong.
class Segment
{
public:
Segment* parent;
list<Segment*> children;
string name;
};
void OpenSegment(Segment* p_segCurrentseg);
void CloseSegment(Segment* p_segCurrentseg);
int _tmain(int argc, _TCHAR* argv[])
{
Segment parent;
parent.name="parent";
Segment* p_segCurrentseg=&parent;
OpenSegment(p_segCurrentseg);
OpenSegment(p_segCurrentseg);
OpenSegment(p_segCurrentseg);
CloseSegment(p_segCurrentseg);
return 0;
}
void OpenSegment(Segment* p_segCurrentseg)
{
Segment child;
child.name="child";
p_segCurrentseg->children.push_front(&child);
child.parent=p_segCurrentseg;
p_segCurrentseg=&child;
}
void CloseSegment(Segment* p_segCurrentseg)
{
p_segCurrentseg=p_segCurrentseg->parent;
}
There are couple of problems in your code.
You are passing p_segCurrentseg by value and assigning to another pointer. This has no effect on the variable in the calling function.
As you already suspected, you are trying to assign p_segCurrentseg to point to a variable that will be gone when you return from the function.
What you can do:
Pass p_segCurrentseg by reference to a pointer.
Create an object from the heap and assign p_segCurrentseg to point to it.
Here's my suggestion for OpenSegment:
void OpenSegment(Segment*& p_segCurrentseg)
{
Segment* child = new Segment;
child->name="child";
p_segCurrentseg->children.push_front(child);
child->parent=p_segCurrentseg;
p_segCurrentseg=child;
}
The problem is in the OpenSegment() method, particularly in these 3 lines:
Segment child;
child.name="child";
p_segCurrentseg->children.push_front(&child);
First, child is a local variable and created on the stack. You then push the address of child into your list. When OpenSegment() returns, the address of child contains garbage since storage for local variables are deallocated.
The solution is to define child as a pointer to Segment, create it on the heap so it lives even after OpenSegment() returns. You have to make sure to deallocate its memory too. The proper place is to define a destructor for your Segment class. In it, iterate through the list (of children segments) and deallocate the memory for each child.
I have created an object of a certain class. The class is "Node" and it has an attribute of CString strName. The value of this variable can be retrieved with a method of Node: CString Node::GetName(), which just returns the name of the variable.
In the following method I instantiate this:
Node* UpperClass::GetObject(CString value) {
Node retObject;
retObject.strName = value;
Trace(retObject.strName); // Prints argument to trace file - this prints the value of strName fine
return &retObject;
}
Then I run this method in a second class:
Node* LowerClass::Get() {
Node *pReturn = instanceOfUpperClass.GetObject();
Trace(pReturn->GetName()); // This trace just prints blank...
return *(&pReturn);
}
As you can see by the code comments, it seems to lose the value when it is passed to the second method. I've attempted to research this but am having some real trouble getting to grips with why.. can anyone help?
As an aside, if one is wondering about the return value of the second method, I am intending to past the resultant pointer to a third function where I utilise it for processing (messy, I know, but I inherited the code and have no choice); just in case that has any bearing on the answer.
Thanks in advance!
int this method:
Node* UpperClass::GetObject(CString value) {
Node retObject;
retObject.strName = value;
Trace(retObject.strName); // Prints argument to trace file - this prints the value of strName fine
return &retObject; // <-- Undefined Baaviour
}
you are returning pointer to local object, which is destroyed once this method ends. You should create retObject dynamically, and return pointer to it, or better put this pointer into shared_ptr<>.
The Node retObject is a local variable when you go out of scope of the function GetObject any use of the object is undefined. And in this case you return a pointer to that object.
I would like to know how delete works?
In main function I have deleted the cfact object. But still the cfact->Hello() works instead of throwing an error.
While debugging I found while delete happens, cfact releases the memory. as soon as factory* c2fact = newfun.Newfun("c2_fact"); line executes cfact gets some memory location.
class factory{
public:
virtual void Hello() = 0;
};
class c_fact: public factory
{
public:
void Hello(){
cout << "class c_fact: public factory"<<endl;
}
};
class c2_fact: public factory
{
public:
void Hello(){
cout << "class c2_fact: public factory"<<endl;
}
};
class callFun{
public:
virtual factory* Newfun(string data)
{
if(data == "c_fact")
{return new c_fact;}
else
{return new c2_fact;}
}
};
class newFun:public callFun{
public:
factory* Newfun(string data)
{
if(data == "c_fact")
{return new c_fact;}
else if (data == "c2_fact")
{return new c2_fact;}
}
};
int main()
{
newFun newfun;
factory* cfact = newfun.Newfun("c_fact");
delete cfact; //Deleted the instance
factory* c2fact = newfun.Newfun("c2_fact");
cfact->Hello();//Still it prints the output
c2fact->Hello();
system("pause");
return 0;
}
delete doesn't actually invalidate what it points to. It just tells the OS that the memory can be used for something else and that the program doesn't need it anymore.
If it not overwritten by other data your data will still be in memory and will still be accessible. This is a cause of many bugs that go undetected during development phase and later show up.
The fact that is is working now doesn't mean it will always work. For example if you move the code to another machine or if you restart your computer the code might segfault.
It is always a good practice to set pointers to NULL after delete. Or even better use smart pointers.
This is undefined behavior, most likely this works because the method Hello is not using any of the classes variables and thus is not using the this pointer. Trying outputting this in Hello and you should see an invalid pointer after the call to delete:
std::cout << std::hex << this << << std::endl ;
In my test case it comes back as 0 after delete
Dereferencing a deleted pointer is undefined behaviour. That means anything can happen, including the program appearing to "work". You cannot rely on any such behaviour.
When you delete the memory it is released. however, the content is usually not changed, so anything that is written in that memory is still there after the delete, but you don't know how long it will stay, as other functions can grab it and overwrite it with their own data.
On some compilers, when compiling in debug mode, the memory is marked, so that you can detect such errors as you did by reusing the deleted pointer. However that is not necessarily the default. So you should never reuse a pointer that was deleted.
Sorry I can't comment...
I compiled your code and you can observe that c2fact replaces the cfact you just destroyed (the output is
class c2_fact: public factory
class c2_fact: public factory
)
BTW if you put "cfact->Hello();" before you create your c2fact, the program may crash (which is what you seem to wish) because the mem blocks are not affected to any object. Note that this behavior may change depending on the memory monitoring and other running processes.