Deallocation of passed in pointer in descructor - c++

class A
{
public:
A(){ };
~A(){ };
//stuff
};
class B
{
public:
B(A* a){ pA = a;}
~B(){ };
A* pA;
};
int main()
{
A instOfA = A();
B instOfB = B(&instOfA);
return 0;
}
I am unsure as to whether ~B() should delete its pointer data member *pA. I.e.
~B()
{
if(pA!=nullptr) delete pA;
}
My guess is that a deletion is needed because B is allocating it in A* pA.

This is all about the ownership and thereby the question is a design question. You are not dynamically allocating A so I would not let B touch it though. It will be deleted in the end of the main.
If you would allocate an instance of A dynamically (A* instOfA = new A();
), then you could choose if you want to pass the ownership of that instance to B and have B deleting it.
My guess is that a deletion is needed because B is allocating it in A*
pA.
Your guess is not right. B is not allocating A. All it does is to take a pointer of the instance that was allocated in the main.

You're guess is incorrect, since
B instOfB = B(&instOfA);
passes the address of an A of automatic storage duration to Bs constructor. Operator delete can only be safely used to destroy an object that was created with the corresponding operator new. Using operator delete to destroy an object that was NOT created with the corresponding operator new gives undefined behaviour.
instOfA is guaranteed to cease to exist when main() returns, so no action is needed to destroy it. And any action which results in it being destroyed twice (so its destructor is called twice on the same object) also gives undefined behaviour.
Generally speaking, it would often be better to design your class B so it manages the A completely (e.g. manage its lifetime) to ensure consistency. By accepting a pointer, it is not possible to prevent (other than by strident documentation, and relying on programmers heeding the documentation) an object being passed to the constructor that the destructor does not handle correctly.
If you are going to do delete pA, it is not necessary to test that pA is non-NULL. The standard specifies that the delete operator has no effect on a NULL pointer.

Related

Is destroying form of operator delete required to actually destroy the object?

C++20 has added destroying form of operator delete distinguished by the std::destroying_delete_t parameter. It causes delete expression to no longer destroy the object prior to invoking operator delete.
The intention is to allow customization of deletion in a way that depends on the object's state, before explicitly invoking the object's destructor and deallocating memory.
However, it isn't clear to me if, when implementing such an operator, I'm actually required to destroy the object. Specifically, am I allowed to have a pool of static objects, and give them out to users who can subsequently treat them as-if they were dynamically allocated? Such that delete expression executed on the object will merely return it to the pool without destroying it. For example, is the following program well-defined?
#include <new>
struct A {
virtual ~A() = default;
};
// 'Regular' dynamically allocated objects
struct B : A {
static A* create() {
return new B();
}
private:
B() = default;
};
// Pooled, statically allocated objects
struct C : A {
static A* create() {
for (auto& c: pool) {
if (!c.in_use) {
c.in_use = true;
return &c;
}
}
throw std::bad_alloc();
}
private:
static C pool[3];
bool in_use = false;
C() = default;
void operator delete(C *c, std::destroying_delete_t) {
c->in_use = false;
}
};
C C::pool[3];
// Delete them identically via the common interface.
void do_something_and_delete(A* a) {
delete a;
}
int main() {
do_something_and_delete(B::create());
do_something_and_delete(B::create());
do_something_and_delete(C::create());
do_something_and_delete(C::create());
}
The purpose of destroying delete operators, as defined by its proposal, is to effectively deal with the ability to create and destroy objects whose deallocation and destruction needs access to the object, for one reason or another. It does this by preventing the automatic invocation of the object's destructor when you invoke delete on objects with a destroying operator delete function. The (still live) object is then passed to the destroying operator delete, so that it can do the deallocation and destruction business.
Its purpose is not to make the statement delete whatever; lie to the user about what this statement accomplishes. But as a consequence of one of the use cases of the feature (virtual destructors without virtual functions), the feature can be (ab)used to lie to the user.
The lifetime of an object ends when its destructor is entered (or when the storage is reused/released). If a destroying operator delete is (ab)used to prevent calling that destructor, then deleteing the object will not end its lifetime.
But lying to the user is a bad idea and you shouldn't do it.

Is there any situation in which an object's storage might change during its lifetime?

I've always assumed that an object begins and ends its lifetime in the same memory location, but I've recently come across a scenario where I need to be sure. Specifically, I'm looking for a guarantee from the standard that no matter what optimizations the compiler performs the address an object is constructed at is the same one that it will have its destructor called from... and that its destructor is, indeed, guaranteed to be called from that location unless the program is terminating.
I've always taken this stuff for granted, but upon closer examination I can't find a guarantee, and there's some language around copy and move elision that I'm not sure how to interpret. I'm hoping that some of the more standards-conversant people here can point me to chapter and verse.
What you are looking for is defined in [intro.object]/1
[...] An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).
This means the address cannot change as long as you can access it.
Specifically, I'm looking for a guarantee from the standard that no matter what optimizations the compiler performs the address an object is constructed at is the same one that it will have its destructor called from...
and that its destructor is, indeed, guaranteed to be called from that location unless the program is terminating.
The standard guarantees both for automatic variables and static variables as long as one doesn't do bad things with the objects. However, it does not guarantee either for objects allocated from the free store.
Even for automatic variables, a crafty programmer can subvert the intention through pointer manipulation and explicitly calling the destructor through a pointer.
In addition, the wrong destructor will be called when delete-ing a base class pointer when the base class does not have a virtual destructor. This will be a programming error, not the result of intention to subvert.
Example:
struct Base
{
int b;
};
struct Derived : virtual Base
{
float d;
};
int main()
{
{
Derived d1; // Not a problem.
}
{
Derived d1;
Derived* ptr = &d1;
delete ptr; // Bad. The programmer subverts the program.
// Must not use delete.
}
{
Derived* d2 = new Derived; // The destructor does not get called automatically.
}
{
Derived* d2 = new Derived;
delete d2; // OK. The proper destructor gets called.
}
{
Derived* d2 = new Derived;
Base* ptr = d2;
delete ptr; // Programmer error. The wrong destructor gets called.
}
}
As mentioned by Nathan Oliver, the standard states that:
[...] An object occupies a region of storage in its period of construction ([class.cdtor]), throughout its lifetime, and in its period of destruction ([class.cdtor]).
Compilers respect this, and there are objects (similar to the one you describe) for which it must hold true. Consider std::mutex. A mutex cannot be copied or moved, and the reason for this is that it must remain at the same location in memory for the duration of it's lifetime in order to work.
So how does copy/move elision work?
Copy/move elision works by creating the object where it needs to go. It's that simple.
We can see this behavior for ourselves:
#include <iostream>
struct Foo {
Foo() {
std::cout << "I am at " << (void*)this << '\n';
}
// Delete copy and move, to ensure it cannot be moved
Foo(const Foo&) = delete;
Foo(Foo&&) = delete;
};
Foo getFoo() {
return Foo();
}
int main() {
Foo* ptr = new Foo(getFoo());
std::cout << "Foo ptr is at " << (void*)ptr << '\n';
delete ptr;
}
This code outputs:
I am at 0x201ee70
Foo ptr is at 0x201ee70
And we see that Foo remains at the same location for the duration of it's lifetime, without ever being copied or moved, even though it's being created in dynamically allocated memory.
How does the compiler know where to create an object?
If a function returns a type that is not trivially copyable, then that function takes an implicit parameter representing the memory address where it's supposed to construct the return value.

C++ Heap destructor when data types are implicitly stored [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Quick question,
I'm new to C++ and I'm having difficulty understanding the destructors.
I'll explain; lets say we have the following;
int _a;
a::a(int x) {
_a = x
}
then we have
a* a1 = new a(8);
I understand that a1's data is created on the heap, and a1 is a pointer, where I'm failing is with the destructor;
a::~a() {
// confusion here
}
Since _a is not a pointer since it was created implicitly on the heap thanks to new (correct) we cannot delete it so what do we do?
Does
delete a1;
call the destructor for a int automatically?
call the destructor for a int automatically?
That would be true if the object were a class type. For non-class types, there is no destrutor, not even implicitly defined ones. Hence, the question of calling the destructor does not arise.
Had your code been something like:
struct Foo
{
Foo() {}
~Foo() {}
};
struct a
{
Foo f
};
a* aptr = new a;
delete aptr;
The destructor, Foo::~Foo(), will be called for f.
I understand what you're driving at and the answer is no, C++ destructors do not automatically destroy the data that your class contains. Unfortunately your example is too contrived to highlight the problem well. int is a primitive type so its destruction is primitive (someone might want to comment on what actually happens in ints destructor). Take the following example:
class A
{
public:
int x;
~A()
{
std::out << "in A destructor" << std::endl;
}
};
class B
{
public:
A* x;
B()
{
x = new A();
}
~B()
{
std::out << "in B destructor" << std::endl;
// does not automatically delete x
}
};
auto x = new B();
delete x;
In this example, constructing an instance of B will also construct an instance of A because you explicitly new it up in the constructor of B. However, unless you explicitly delete x in your destructor for B it will not automatically be deleted.
A slight variation of me previous example would be if B::x were of type A and not A*, in which case the answer is yes, the destructor for A would be called.
I hope this helps!
The destructor is just a function that is called automatically when the instance comes out of scope. It's a convenient way to release dynamically allocated memory.
You don't have to worry about releasing variables that were allocated on the stack (anything that is declared and not new-ed).
For example:
int localStackVar = 5; //no need to deallocate explicitly
int* localPointer = &localStackVar // no need to deallocate explicitly
int* heapValue = new int(); //Allocates to the heap so you need to call delete explicitly
The first two from the example above are on the stack, the first one is an int and the second is an int pointer, which is just a way to say it's a variable that holds the memory address of another variable.
Both of those will be deallocated automatically, since you did not call new on them.
The third line allocates an int on the heap. You have to call delete on it when you don't need it anymore.
If those 3 variables were a part of a class, your constructor and destructors would look like this:
MyClass::MyClass()
{
heapValue = new int();
}
MyClass::~MyClass() //destructor
{
delete heapValue;
}
void someFun()
{
MyClass instance; //constructor is called here
//do stuff
return; //destructor is called here
}
So while MyClass instance is a local stack variable when declared in someFun
since the constructor is called automatically, heapVal is made to point to a memory location that is on the heap which needs to be released explicitly.
If your destructor did not call delete on it, the memory would "leak" it will not be released until your program terminates.

Why there are no memleaks in the following C++ while assign?

the following code demotes my belief that I know C++ more or less. Why valgrind does not show any memleak here? Why I expect memleaks:
B is larger than A: it contains an additional member; so on assign there should be class' fields slicing.
~A() does not have a virtual dtor. So when we call delete a only ~A() should be called and memory allocated in B would lost.
But I receive that the calling order of dtors is: ~A(), ~B(), ~A(). Why?!
struct A {
~A()
{
std::cerr << "~A" << std::endl;
}
};
struct B : A {
int* data;
B() : data(new int[20]) {}
~B()
{
std::cerr << "~B" << std::endl;
delete [] data;
}
};
main():
A* a = new A;
B* b = new B;
*a = *b;
delete a;
delete b;
UPD:
Shame on me! I muddled deletion of an object by the pointer of base class when virtual dtor should called. Here just contents of class copying. Thanks everyone!
delete a;
a is A*, so A::~A is called
delete b;
b is B* so B::~B is called.
Why would there be a problem?
Class fields' slicing? Yeah, so? You're just copying the A fields from *b to *a, nothing more than that. No memory is lost here.
In *a = *b you are copying (and yes, slicing) *b to *a. However, that leaves *b unchanged; it doesn't get sliced. When you delete b, you are asking for ~B() to be called on *b.
The *a = *b; assignment only copy the common A part of the data (and A has no fields).
You made a delete for each new , so there is no memleak.
*a =*b
does not allocate anything, the copy constructor just copies the part of b which can go to a, but it does not call new..
By invoking *a = *b;, you're implicitly calling the assignment operator function created by the compiler that looks like this:
A &operator=( const A &other ){
}
which in your case doesn't do anything since A has no member variable.
Your class A is empty, so it is entirely irrelevant for the purpose of this discussion. The only code that is involved in dynamic allocation is:
B* b = new B;
delete b;
Since you delete an object created with new, there is no leak. Furthermore, the class B contains sufficient code to clean up its own internal allocation in this straight-forward use-case.
(Note that class B is still horribly broken, since it will not survive copying or assignment. The classic Rule of Three (or Five).)
Because what you do here is object slicing. I think you intended to have the base pointer point to the derived object and since the base destructor is not virtual, derived class destructor not called during cleanup. But that is not the case here.
*a = *b
The compiler will 'slice' those derived part of the object and copy only the base part of the object. This is not usually one want to do because this will result in an incomplete object with only base class properties and specialized derived class properties missing.

Overriding function in C++ doesn't work

#include <cstdio>
using namespace std;
class A {
public:
virtual void func() { printf("A::func()"); }
};
class B : public A {
public:
virtual void func() { printf("B::func()"); }
};
int main() {
A a = *(A *)new B();
a.func();
}
The question is simple: why a->func() calls function in class A even though a contains object of class B?
A a = *(A *)new B();
a.func();
Here's what happens in this code, step by step:
new B(): a new object of type B is allocated on the free store, resulting in its address
(A*): the address of the object is cast to A*, so we have a pointer of type A* actually pointing to an object of type B, which is valid. All OK.
A a: here the problems start. A new local object of type A is created on the stack and constructed using the copy constructor A::A(const A&), with the first paremeter being the object created before.
The pointer to the original object of type B is lost after this statement, resulting in a memory leak, since it was allocated on the free store with new.
a.func() - the method is called on the (local) object of class A.
If you change the code to:
A& a = *( A*) new B();
a.func();
then only one object will be constructed, its pointer will be converted to pointer of type A*, then dereferenced and a new reference will be initialized with this address. The call of the virtual function will then be dynamically resolved to B::func().
But remember, that you'd still need to free the object since it was allocated with new:
delete &a;
Which, by the way, will only be correct if A has a virtual destructor, which is required that B::~B() (which luckily is empty here, but it doesn't need to in the general case) will also be called. If A doesn't have a virtual destructor, then you'd need to free it by:
delete (B*)&a;
If you would want to use a pointer, then that's the same as with the reference. Code:
A* a = new B(); // actually you don't need an explicit cast here.
a->func();
delete (B*)a; // or just delete a; if A has a virtual destructor.
Now that you've modified your code snippet, the problem is clear. Polymorphism (i.e. virtual functions) are only invoked via pointers and references. You have neither of these. A a = XXX does not contain an object of type B, it contains an object of type A. You've "sliced away" the B-ness of the object by doing that pointer cast and dereference.
If you do A *a = new B();, then you will get the expected behaviour.
The problem you encounter is classic object slicing :
A a = *(A *)new B();
Make a either a reference or pointer to A, and virtual dispatch will work as you expect. See this other question for more explanations.
You commented on another answer that "Compiler should at least give warning or what". This is why is it considered a good practice to make base classes either abstract of non copyable : your initial code wouldn't have compiled in the first place.
This might do that trick.
A &a = *(A *)new B();
a.func();
Or
A *a = new B();
a->func();
Virtual dispatch works only with pointer or reference types:
#include <cstdio>
using namespace std;
class A {
public:
virtual void func() { printf("A::func()"); }
};
class B : public A {
public:
virtual void func() { printf("B::func()"); }
};
int main() {
A* a = new B();
a->func();
}
The problem is the deference and casting of B to A with the A a = *(A *)new B();
You can fix it with just removing the *(A *) changing it to (A *a = new B(); ) but I would take it a step further since your variable name is not good for instantiation of B.
It should be
B *b = new B();
b->func();
Because you performed slicing when you copied the dynamically allocated object into object a of type A (which also gave you a memory leak).
a should be a reference (A&) instead, or just keep the pointer.