I think this is probably a really simple question, but I am as much a C++ developer as the guys at the walmart meat counter are butchers.
Say I have:
class Parent{
protected:
~Parent(){};
};
class ChildA : public Parent{
};
struct Container{
Parent *child;
//Tried this, causes: munmap_chunk(): invalid pointer
~Container(){
delete &child;
}
};
Container MakeStruct(){
ChildA child = *new ChildA();
return Container { .child = &child };
}
int main()
{
Container cont = MakeStruct();
//Tried this, causes: "Parent::~Parent()" is inaccessible
delete cont.child;
}
As you can see, I am using new
to create a ChildA
because I need it to outlive the MakeStruct
function. So I know this means that child
(in MakeStruct
) will be placed on the heap, and that I am responsible for deleting it. But I can't seem to delete it.
I can't change the type of child
in Container
because I need it to accept both a ChildA
and a ChildB
. It sort of makes sense, considering the destructor of Parent
is protected. I have no control over Parent
or either Child
. They are part of an external library.
I case it helps, the actual code I'm working with is a library called ArduinoJson.
I am trying to return either a DynamicJsonDocument
or a StaticJsonDocument<T>
from a function, wrapped in a struct taking a JsonDocument
:
Here is the struct that contains the JsonDocument
:
struct rpc_handler_result_t {
esp_err_t result;
JsonDocument *response;
};
which is returned from:
{
const int len = JSON_OBJECT_SIZE(1);
StaticJsonDocument<len> reply = *new StaticJsonDocument<len>;
reply["MaxOutput"] = Configuration::GetMaxOutputAmps();
rpc_handler_result_t res = {
.result = ESP_OK,
.response = reply
};
return res;
}
When you eventually call delete
, you must pass it precisely the value you got from new
. So you must store the value that new
returns somewhere. But look at your call to new
-- it dereferences that value and never stores it anywhere. So how can you call delete
?!
Container MakeStruct(){
ChildA child = *new ChildA(); // The value returned by new is lost here
return Container { .child = &child }; // child is a local object here
}
This is all wrong. You create a new object by calling new
. But you do not store the value new
returned anywhere. Now, child
is a temporary object whose value was copy-constructed from the value of the object you allocated with new
and leaked.
Then, you save the address of the temporary child
object you created on the stack. But that object won't exist after you return
.
What you wanted to do was save the value that new
returned. But you got rid of it immediately by dereferencing it and never saving it.
So:
new
returns so you can delete
it later.You wanted .child = new ChildA()
, setting the child
member to be a pointer to the object created by new
, not a pointer to some temporary, local object. You can save the value new
returns in a temporary if you want, just make sure .child
gets the value new
returned and not any other value.
Also:
Parent *child;
//Tried this, causes: munmap_chunk(): invalid pointer
~Container(){
delete &child;
}
This is wrong too. What type is &child
? Is &child
something you got from new
? This should be delete child;
.