This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
deleting dynamically allocated object that contains vector in C++ STL
I have a struct like this
struct foo {
vector<int> myvector;
};
Now, I create a pointer to foo, resize and insert some elements into the vector.
foo *myfoo = new foo;
myfoo->myvector.resize(100);
myfoo->myvector.push_back(0);
myfoo->myvector.push_back(1);
... // and so on
Now, before myfoo goes out of scope, I would have to deallocate the memory allocated to it with
delete myfoo;
My question is whether this would take care freeing myvector also? I have this particular query because now that myvector is resized, the STL library would presumably allocated the container in the heap. So, when I free up myfoo, I wouldn't want the memory allocated to myvector leaking.
Yes, deleting myfoo will destroy all of its members too, which includes the std::vector. It's important to note that if you had pointers inside foo, only the pointers would be destroyed, not the objects they point to (unless of course you defined a destructor that did that job for you - which you should!).
It is mandated by the standard that after execution of the destructor, any non-static data members are destroyed also (§12.4/8):
After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X's direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X's virtual base classes.
The class foo has a defaulted destructor because no user-declared destructor is defined (§12.4/4):
If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (8.4).
The destructor of myfoo is called when it is deleted (§5.3.5/6):
If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted.
A delete-expression is an expression of the form:
::opt delete cast-expression
Calling delete foo will deallocate and call destructors (if applicable) on all members of foo, so yes. If it didn't work this way the language would be much more difficult to use.
The struct foo just holds the container of a vector. The items of the vector are allocated separately (usually on the heap) anyway.
The vector's destructor deletes the actual vector on the heap, and the vector is destroyed when the object is deleted.
Here is code example that answers your question.
#include <iostream>
struct bar {
~bar() {std::cout << "deleted bar" << std::endl;}
};
struct foo {
bar b[10];
};
int main() {
foo* f = new foo();
delete f;
}
The program will print "deleted bar" 10 times.
Related
I have this example:
struct A{
A(){std::cout << "A's def-ctor\n";}
~A(){std::cout << "A's dtor\n";}
A(A const&){std::cout << "A's copy-ctor\n";}
A& operator = (A const&){std::cout << "A's copy-assign op\n"; return *this; }
};
struct Foo{
Foo() : curMem_(INT), i_(0){}
~Foo(){
if(curMem_ == CLS_A) // If I comment out this line then what happens?
a_.~A();
}
enum {INT, CHAR, CLS_A, BOOL} curMem_;
union{
int i_;
char c_;
A a_;
bool b_;
};
};
Foo f;
f.curMem_ = Foo::CLS_A;
f.a_ = A();
f.curMem_ = Foo::BOOL;
f.b_ = true;
We know that a class default destructor doesn't know which member of a class's member of a union type is active that is why we do need to define out version of destructor. So union's member data of class type are not automatically destroyed. So What will happen if I don't explicitly call the destructor of those class type member of the union?
If I comment the line in Foo destructor or remove the destructor itself what will happen? Is it undefined behavior?
My class A doesn't manage a resource via a raw pointer then why I bother to explicitly call its destructor when an of object of it is a member of a union? Thank you!
P.S: I have this from C++ primer 5th edition Chapter 19.6 unions:
Our destructor checks whether the object being destroyed holds a string. If so, the destructor explicitly calls the string destructor (§ 19.1.2, p. 824) to free the memory used by that string. The destructor has no work to do if the union holds a member of any of the built-in types.
"The destructor has no work to do if the union holds a member of any of the built-in types." I think he could add: "or of a class type which depends on the trivial destructor". What do you think?
The exact wording of the standard given in [basic.life]p6 is:
For an object of a class type, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression ([expr.delete]) is not used to release the storage, the destructor is not implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.
(emphasis mine)
"depends on the side effects" seems pretty vague, and there are plenty of questions on stack overflow discussing this wording. Your A class's destructor seems to have the side effect of calling an I/O function, so it seems like you run into undefined behaviour.
Even if it wasn't UB, if it was a std::vector, std::string or std::fstream, you would leak resources like memory or file handles. It depends entirely on what the destructor of the class (and any members of that class) do.
Since "My class A doesn't manage a resource via a raw pointer", it should really have a trivial destructor. In which case, this point is moot and it is fine to not call the destructor.
I would like to recycle memory for an object rather than deallocating and reconstructing it. Is the following usage of "placement new" safe, assuming that Foo in practice does not contain pointers (but might contain functions)?
Also, is the final delete call safe, and will it correctly call the destructor on the second "new" object, and correctly free the memory afterwards?
#include <new>
struct Foo {
int hello;
int world;
};
int main() {
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
new(foo) Foo();
delete(foo);
}
The simple example above compiles and runs without errors, but I cannot tell by running it whether it might blow up for some reason in a more complex environment.
It's safe because the object you're overwriting has a trivial destructor. From n3337, chapter 3.8 (Object lifetime):
4 A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly
calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type
with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage
which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a
delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and
any program that depends on the side effects produced by the destructor has undefined behavior.
The delete call is safe, too. You're calling it on a pointer that you got from new and there's a live object at that place.
And as you hinted in the question, it could invoke undefined behaviour if the destructor is non-trivial and has side effects - you need to call it explicitly in that case. Whether or not the class contains pointers is not directly important - reusing the storage is safe even in that case, but of course, you could introduce memory leaks and other bugs that way.
No, it is not dangerous to reuse memory of an object, provided that you are doing it correctly. Moreover, you do not have to restrict yourself to objects that have no pointers: by calling the destructor explicitly you can prepare the object for reuse, like this:
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
foo->~Foo(); // Call the destructor explicitly to clean up the resources of a Foo
new(foo) Foo(); // Place new data into the previously allocated memory
delete(foo); // We are deleting a fully initialized object, so it is OK
There have been two answers already, but they give, I fear, an incomplete picture.
You may reuse the storage of an object, providing that you respect a few conditions:
You need not use a dynamically allocated object, any object is fine.
You should properly destroy the previous object, by calling its destructor (explicitly); failure to do so leads to undefined behavior if the destructor has side-effects (see §3.8/4)
The object that you place should have the same dynamic type as the previous object (see §3.8/7)
Let us review them, starting with any object is fine:
struct Foo {
int hello;
int world;
};
void automatically_allocated() {
Foo foo;
foo.~Foo();
new (&foo) Foo{};
}
void dynamically_allocated() {
std::unique_ptr<Foo> foo(new Foo{});
foo->~Foo();
new (&*foo) Foo{};
}
Let use continue with destroy the previous object:
struct Bar {
int hello;
std::string world;
};
void UNDEFINED_BEHAVIOR() {
Bar bar;
new (&bar) Bar{}; // most likely scenario: leaks memory owned by bar.world
}
And finally with same dynamic type:
struct Base { virtual ~Base() {} };
struct Derived: Base { std::string world; };
struct Other: Base { int hello; }
void UNDEFINED_BEHAVIOR() {
Derived derived;
Base& b = derived;
b.~Base(); // fine
new (&b) Other{};
// Most likely here, calls "derived.~Derived()" on an object of type Other...
}
For a simple class like this:
class X {
public:
//...
private:
int *ptr;
};
X::~X() {
delete ptr;
}
I have written a destructor to free the memory pointed to by ptr. Now, I am wondering, if my destructor stays like this, when is ptr actually destroyed?
Thanks
I think this article might answer most of your questions
"Destructors are implicitly called when an automatic object (a local
object that has been declared auto or register, or not declared as
static or extern) or temporary object passes out of scope. They are
implicitly called at program termination for constructed external and
static objects. Destructors are invoked when you use the delete
operator for objects created with the new operator."
More specifically:
"The destructors of base classes and members are called in the reverse
order of the completion of their constructor:
The destructor for a class object is called before destructors for
members and bases are called.
Destructors for nonstatic members are called before destructors for
base classes are called.
Destructors for nonvirtual base classes are called before destructors
for virtual base classes are called."
delete invokes the destructor of the object that is being deleted and then frees the memory it occupied.
The destructor will calls in the end of scope where the specific instance are.
The local version of ptr for a given instance of X will be destroyed when the object goes out of scope. For example:
int main()
{
X obj;
for (int i=0; i<10; i++) {
X tmp;
// do work with tmp
...
// tmp goes out of scope here
// the destructor tmp::~X will be called here, immediately after each iteration ends
}
// obj goes out of scope here
// the destructor obj::~X called when the program ends
}
Does the default destructor in C++ classes automatically delete members that are not explicitly allocated in code? For example:
class C {
public:
C() {}
int arr[100];
};
int main(void) {
C* myC = new C();
delete myC;
return 0;
}
Does delete myC deallocate myC's arr automatically? Or do I need to write C's destructor to do this explicitly?
The constructor (in the absence of any ctor-initializer-list) calls the default constructor for each subobject.
Since you have no base classes and your member variables are primitive types, it will do nothing at all.
Same with the destructor. Yours is implicitly compiler-generated since you haven't declared one, and it will call the destructor for each subobject. Again that's trivial because your only subobject is an aggregate of primitives.
Now, all memory of the class will be freed when you delete it. Since the array is embedded inside the class, it's part of the same memory region and will be freed at the same time.
The implicitly defined (default) destructor will call the destructor for each member. In the case of a member array, it will call the destructor for each element of the array.
Note that pointers don't have destructors; you need to manually delete them. You don't have this problem in the provided example, but it's something to be aware of.
If your class/struct contains a pointer, and you explicitly allocate something for that pointer to refer to, then you normally need to write a matching delete in the dtor. Members that are directly embedded into the class/struct will be created and destroyed automatically.
class X {
int x;
int *y;
public:
X() : y(new int) {}
~X() : { delete y; }
};
Here X::x will be created/destroyed automatically. X::y (or, to be technically correct, what X::y points at) will not -- we allocate it in the ctor and destroy it in the dtor.
Anything that you call new for must have a corresponding delete. If you didn't call new to create an instance of something then you don't have to call delete.
You don't have to write a destructor. C++ class has the default destructor to delete the object after 'return 0' to recycle the memory.
For a programming assignment, we are given a template class with two members declared not as pointers, but actual objects:
Foo member;
In the constructor, I tried member = *(new Foo()); initially, but learned that, at least sometimes, it was copying the new Foo object, and therefore causing memory leaks.
I finally discovered member = Foo(), and then looked up what the difference was. I learned that member will be allocated on the stack instead of the heap, and that it will be deleted once it is out of scope. How does this work for objects, though?
Is member only deleted when the parent / class object is deleted?
I also have another question about member = *(new Foo());. I was initializing two member variables of the same type:
// Members
Foo member1;
Foo member2;
// Constructor {
member1 = *(new Foo());
member2 = *(new Foo());
}
For some reason it seemed member1 was not being copied and it retained the same address as the initial Foo (i.e. there was no memory leak when it was deleted). member2 however, would be copied and had a different address, and memory was leaked. Is there an explanation for this?
Your analysis is incorrect. Both of these are memory leaks. What you are doing is allocating a new copy of the object, assigning the value to the member, and then discarding the pointer to the allocated memory without freeing that memory. It is a memory leak in both cases.
Now, consider the following code:
class MemberType {
public:
MemberType() { std::cout << "Default constructor" << std::endl; }
MemberType(int) { std::cout << "Int constructor" << std::endl; }
};
class Example1 {
public:
Example1() {}
private:
MemberType member_;
};
class Example2 {
public:
Example2() : member_(5) {}
private:
MemberType member_;
};
int main(int argc, char** argv) {
Example1 example1;
Example2 example2;
return 0;
}
This code will print both different types of constructors. Note that it did not take any initialization code at all for the member to be initialized in the default manner. Hence your new statement (or even an assignment without new) would be unnecessary in the default initialization case. When initializing members using a constructor other than the default constructor, the proper way to do this is with an initializer list. (The initializer list is what is happening with ": member_(5)" in the example.
Please see the C++ FAQ on constructors for more information about constructing objects in C++.
member = *(new Foo());
new Foo() dynamically allocates a Foo object and returns a pointer to that object. The * dereferences that pointer, giving you the Foo object. This object is then assigned to member, which involves calling the Foo copy assignment operator. By default, this operator assigns the values of each of the members of the right-hand side (the *(new Foo())) object into the left-hand side object (the member).
The problem is this: new Foo() dynamically allocates a Foo object and that object is not destroyed until you delete the pointer returned from the new. You don't save that pointer anywhere, so you've leaked the dynamically allocated object.
This is not the correct way to initialize an object.
member = Foo();
This creates a temporary, initialized Foo object and this object is assigned to member. At the end of this statement (at the ;, effectively), the temporary object is destroyed. member is not destroyed, and the contents of the temporary Foo object were copied into member, so this is exactly what you want to do.
Note that the preferred way to initialize member variables is using the initializer list:
struct C {
Foo member1, member2;
C() : member1(), member2() { }
};