Freeing memory after using placement new c++ - c++

I was trying to solve a problem that I ran into while programming the ESP8266 MCU, I basically needed to declare an object as global so that it wouldn't cause issues with the callbacks that one of the libraries does when the user sends an HTTP request, but I also needed to wait until I had some data from the EEPROM before calling the constructor so a lot of people told me that I should use placement new which worked perfectly for what I was trying to do. There's still something I don't understand though: after I have called the constructor for the object since it was declared globally and I'm trying to keep it around I shouldn't delete it by calling the destructor, but should I delete the first pointer that I used to save the object (I'm not entirely sure if I'm wording this right)?
class display{
public:
display(int b){
std::cout<<"the value of a: "<<b;
}
};
char *memory= new char[sizeof(display)];
display *obj;
int main(){
int a=69;
obj=new(memory) display(a);
return 0;
}
That is more or less what I did in the code for the ESP (without all the other stuff, but it is the same in terms of what I tried to do with placement new). My question is after someone does something like that, would it cause issues if I were to delete *memory or is it not necessary?

There is no need for the allocating new here. You just need to make sure that you have an array of sufficient size and alignment:
alignas(display) std::byte memory[sizeof(display)];
display *obj = nullptr;
(Instead of std::byte you can use unsigned char, but I think std::byte, which is available since C++17, expresses the intent as raw memory storage better.)
Then construct the object with
obj = new(memory) display(a);
and when it is not needed anymore, call its destructor explicitly:
obj->~display();
No delete is needed in this case. With your approach an additional delete[] memory; after the destructor call would be required to free the memory allocated with the first new, if you don't intent to reuse it after the destructor call (which you can do e.g. in a loop constructing a new display with placement-new). Note that you need to call the destructor on obj and the delete[] on memory. This is not interchangeable. memory is a pointer to the allocated memory block and obj a pointer to the object nested in it. The former was allocated with allocating new[], so required delete[], and the latter was only created with the (non-allocating) placement-new, so requires only an explicit destructor call.
Of course, you can consider whether the destructor call is really needed. If the display doesn't hold any resources that need to be cleaned up, then you can skip it, although I would be safe and call it anyway, just in case display will be changed later.
Also, the standard library since C++17 implements all of this as std::optional. If you can use it, then do so:
std::optional<display> obj;
// obj is now empty, can be tested with `if(obj)`
obj.emplace(/* constructor arguments */);
// obj now contains a display that can be accessed like a pointer with * and ->
// destructor of obj will take care of correctly destroying the display
emplace can also be called multiple times to replace the display with a new one (and calling the old one's destructor) or .reset() can be used to explicitly empty the optional.
If you don't have C++17 available, a std::unique_ptr can be used in a similar way, except that it will use a heap allcoation, which std::optional doesn't, and that std::unique_ptr isn't copyable even if display is, while std::optional will be.
std::optional<display> obj;
// obj is now empty, can be tested with `if(obj)`
obj = std::make_unique<display>(/* constructor arguments */);
// obj now contains a display that can be accessed like a pointer with * and ->
// destructor of obj will take care of correctly destroying the display
obj can be reassigned in that way multiple times as well or reset with = nullptr; or .reset() and in either case it will take care of correctly destroying any display just like std::optional does.

Related

Will this completely clean up the result of dynamic allocation of a class object?

So I dynamically allocated a class object with this code:
void Inventory::createNewInventoryItem(std::string itemName, unsigned int maxQuantity, unsigned int orderThreshold, double price)
{
InventoryItems* newItem = new InventoryItems;
newItem->createInventoryItem(itemName, maxQuantity, orderThreshold, price);
m_inventory.push_back(newItem);
}
Which is stored in this vector: std::vector<InventoryItems*> m_inventory;
Then once the object is done being used deleteInventoryItem is called, which is defined as:
void Inventory::deleteInventoryItem(int posInVector)
{
m_inventory.at(posInVector)->~InventoryItems();
m_inventory.erase(m_inventory.begin() + posInVector);
}
My question is: Will this deleteInventoryItem function successfully free up the memory used by the dynamic allocation in createNewInventoryItem? (This ties into my confusion around if delete[] is needed when a class deconstructor is called)
Sorry for the not "Mission critical" question, just trying to make sure I'm not continuing bad practices as I'm really trying to program as perfectly as I could...
Will this deleteInventoryItem function successfully free up the memory used by the dynamic allocation in createNewInventoryItem?
No, your code does leak memory. What you do here,
m_inventory.at(posInVector)->~InventoryItems();
is explicitly calling the destructor of the container element. This does clean up any resources held by the specific object, but not the memory resource that hosts the object itself. It is very, very rare that you have to manually call the destructor of an object (the only situation I can think of is using placement new, and you very rarely need that).
What you could have done is using delete to both clean up the memory and invoke the destructor of the element being erased. But as a much safer alternative for this manual memory management, I would advise you to choose one the following two options
If the object that is supposed to be stored in the container fine with being copied by value (i.e. not a polymorphic type and you want to store base class references), just store it by value:
std::vector<InventoryItems> myData;
Otherwise, store a std::unique_ptr which takes care of all the memory managent for you:
std::vector<std::unique_ptr<InventoryItems>> myData;
No it will memory-leak. You are obviously calling the destructor but do not call delete which is the counterpart of new. The new followed by a type allocates memory first then calls implicitly the destructor. The delete operator also does two things, first calling the destructor, then deallocate the memory.
There is rarely a need for explicitly calling the destructor, specifically for cleaning up instances created through the new placement syntax., and not calling ~ it in this case will lead to leaks if the instance contains hold dynamically bound resources via members or base class(es).
As a rule of thumb, keep these pairs in mind:
obj = new Class; needs delete obj;
obj = new (buffer) Class needs obj->~Class();
array = new Class[count]; needs delete [] array;
... and, as the most important in the collection, automatic objects:
Class obj; needs (nothing) but the end of the enclosing scope
The last "pair" shows an implicit call to (default) constructor (it could be any other constructor provided by the Class definition) and ends (at the closing brace) with an implicit call of the destructor, which, by the way, the reason for the C++ language to limit the destructors of a class to at maximum one: The compiler depends on this uniqueness to be able to automatically close scopes. This very automatism also forms the basis for std::unique_ptr and std::shared_ptr.

Is destroying then constructing at this inside member function defined behavior? [duplicate]

I want to reset an object. Can I do it in the following way?
anObject->~AnObject();
anObject = new(anObject) AnObject();
// edit: this is not allowed: anObject->AnObject();
This code is obviously a subset of typical life cycle of an object allocated by in placement new:
AnObject* anObject = malloc(sizeof(AnObject));
anObject = new (anObject) AnObject(); // My step 2.
// ...
anObject->~AnObject(); // My step 1.
free(anObject)
// EDIT: The fact I used malloc instead of new doesn't carry any meaning
The only thing that's changed is the order of constructor and destructor calls.
So, why in the following FAQ
all the threatening appear?
[11.9] But can I explicitly call a
destructor if I've allocated my object
with new?
FAQ: You can't, unless the object was
allocated with placement new. Objects
created by new must be deleted, which
does two things (remember them): calls
the destructor, then frees the memory.
FQA: Translation: delete is a way to
explictly call a destructor, but it
also deallocates the memory. You can
also call a destructor without
deallocating the memory. It's ugly and
useless in most cases, but you can do
that.
The destructor/constructor call is obviously normal C++ code. Guarantees used in the code directly result from the in placement new guarantees. It is the core of the standard, it's rock solid thing. How can it be called "dirty" and be presented as something unreliable?
Do you think it's possible, that the in-placement and non-in-placement implementation of new are different? I'm thinking about some sick possibility, that the regular new can for example put size of the memory block allocated before the block, which in-placement new obviously would not do (because it doesn't allocate any memory). This could result in a gap for some problems... Is such new() implementation possible?
Don't get sucked in by the FQA troll. As usual he gets the facts wrong.
You can certainly call the destructor directly, for all objects whether they are created with placement new or not. Ugly is in the eye of the beholder, it is indeed rarely needed, but the only hard fact is that both memory allocation and object creation must be balanced.
"Regular" new/delete simplifies this a bit by tying memory allocation and object creation together, and stack allocation simplifies it even further by doing both for you.
However, the following is perfectly legal:
int foo() {
CBar bar;
(&bar)->~CBar();
new (&bar) CBar(42);
}
Both objects are destroyed, and the stack memory is automatically recycled too. yet unlike the FQA claims, the first call of the destructor is not preceded by placement new.
Why not implement a Clear() method, that does whatever the code in the body of the destructor does? The destructor then just calls Clear() and you call Clear() directly on an object to "reset it".
Another option, assuming your class supports assignment correctly:
MyClass a;
...
a = MyClass();
I use this pattern for resetting std::stack instances, as the stack adaptor does
not provide a clear function.
Technically it is bad practice to call constructors or destructors explicitly.
The delete keyword ends up calling them when you use it. Same goes for new with constructors.
I'm sorry but that code makes me want to tear my hair out. You should be doing it like this:
Allocate a new instance of an object
AnObject* anObject = new AnObject();
Delete an instance of an object
delete anObject;
NEVER do this:
anObject->~AnObject(); // My step 1.
free(anObject)
If you must "reset" an object, either create a method which clears all the instance variables inside, or what I would recommend you do is Delete the object and allocate yourself a new one.
"It is the core of the language?"
That means nothing. Perl has about six ways to write a for loop. Just because you CAN do things in a language because they are supported does mean you should use them. Heck I could write all my code using for switch statements because the "Core" of the language supports them. Doesn't make it a good idea.
Why are you using malloc when you clearly don't have to. Malloc is a C method.
New and Delete are your friends in C++
"Resetting" an Object
myObject.Reset();
There you go. This way saves you from needlessly allocating and deallocating memory in a dangerous fashion. Write your Reset() method to clear the value of all objects inside your class.
You cannot call the constructor in the manner indicated by you. Instead, you can do so using placement-new (like your code also indicates):
new (anObject) AnObject();
This code is guaranteed to be well-defined if the memory location is still available – as it should be in your case.
(I've deleted the part about whether this is debatable code or not – it's well-defined. Full stop.)
By the way, Brock is right: how the implementation of delete isn't fixed – it is not the same as calling the destructor, followed by free. Always pair calls of new and delete, never mix one with the other: that's undefined.
Yes, what you are doing is valid most of the time. [basic.life]p8 says:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
the storage for the new object exactly overlays the storage location which the original object occupied, and
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
neither the original object nor the new object is a potentially-overlapping subobject ([intro.object]).
So it is legal if you don't have a const or reference member.
If you don't have this guarantee, you need to use std::launder or use the pointer returned by placement new (like you're doing anyways) if you want to use the new object:
// no const/ref members
anObject->~AnObject(); // destroy object
new (anObject) AnObject(); // create new object in same storage, ok
anObject->f(); // ok
// const/ref members
anObject->~AnObject();
auto newObject = new (anObject) AnObject();
anObject->f(); // UB
newObject->f(); // ok
std::launder(anObject)->f(); // ok
Note that they're not malloc and free that are used, but operator new and operator delete. Also, unlike your code, by using new you're guaranteeing exception safety. The nearly equivalent code would be the following.
AnObject* anObject = ::operator new(sizeof(AnObject));
try
{
anObject = new (anObject) AnObject();
}
catch (...)
{
::operator delete(anObject);
throw;
}
anObject->~AnObject();
::operator delete(anObject)
The reset you're proposing is valid, but not idiomatic. It's difficult to get right and as such is generally frowned upon and discouraged.
Why not reset using the operator=()? This is not debatable and by far more readable.
A a;
//do something that changes the state of a
a = A(); // reset the thing
You can't call the constructor like that, but there's nothing wrong with reusing the memory and calling placement new, as long you don't delete or free (deallocate) the memory. I must say reseting an object like this is a little sketchy. I would write an object to be explicitly resetable, or write a swap method and use that to reset it.
E.g.
anObject.swap( AnObject() ); // swap with "clean" object
If your object has sensible assignment semantics (and correct operator=), then *anObject = AnObject() makes more sense, and is easier to understand.
It is far better just to add something like a Reset() method to your object rather than play with placement new's.
You are exploiting the placement new feature which is intended to allow you to control where an object is allocated. This is typically only an issue if your hardware has "special" memory like a flash chip. IF you want to put some objects in the flash chip, you can use this technique. The reason that it allows you to explicitly call the destructor is that YOU are now in control of the memory, so the C++ compiler doesn't know how to do the deallocation part of the delete.
It is not saving you much code either, with a reset method, you will have to set the members to their starting values. malloc() doesn't do that so you are going to have to write that code in the constructor anyway. Just make a function that sets your members to the starting values, call it Reset() call it from the constructor and also from anywhere else you need.

C++ placement new for local objects [duplicate]

I want to reset an object. Can I do it in the following way?
anObject->~AnObject();
anObject = new(anObject) AnObject();
// edit: this is not allowed: anObject->AnObject();
This code is obviously a subset of typical life cycle of an object allocated by in placement new:
AnObject* anObject = malloc(sizeof(AnObject));
anObject = new (anObject) AnObject(); // My step 2.
// ...
anObject->~AnObject(); // My step 1.
free(anObject)
// EDIT: The fact I used malloc instead of new doesn't carry any meaning
The only thing that's changed is the order of constructor and destructor calls.
So, why in the following FAQ
all the threatening appear?
[11.9] But can I explicitly call a
destructor if I've allocated my object
with new?
FAQ: You can't, unless the object was
allocated with placement new. Objects
created by new must be deleted, which
does two things (remember them): calls
the destructor, then frees the memory.
FQA: Translation: delete is a way to
explictly call a destructor, but it
also deallocates the memory. You can
also call a destructor without
deallocating the memory. It's ugly and
useless in most cases, but you can do
that.
The destructor/constructor call is obviously normal C++ code. Guarantees used in the code directly result from the in placement new guarantees. It is the core of the standard, it's rock solid thing. How can it be called "dirty" and be presented as something unreliable?
Do you think it's possible, that the in-placement and non-in-placement implementation of new are different? I'm thinking about some sick possibility, that the regular new can for example put size of the memory block allocated before the block, which in-placement new obviously would not do (because it doesn't allocate any memory). This could result in a gap for some problems... Is such new() implementation possible?
Don't get sucked in by the FQA troll. As usual he gets the facts wrong.
You can certainly call the destructor directly, for all objects whether they are created with placement new or not. Ugly is in the eye of the beholder, it is indeed rarely needed, but the only hard fact is that both memory allocation and object creation must be balanced.
"Regular" new/delete simplifies this a bit by tying memory allocation and object creation together, and stack allocation simplifies it even further by doing both for you.
However, the following is perfectly legal:
int foo() {
CBar bar;
(&bar)->~CBar();
new (&bar) CBar(42);
}
Both objects are destroyed, and the stack memory is automatically recycled too. yet unlike the FQA claims, the first call of the destructor is not preceded by placement new.
Why not implement a Clear() method, that does whatever the code in the body of the destructor does? The destructor then just calls Clear() and you call Clear() directly on an object to "reset it".
Another option, assuming your class supports assignment correctly:
MyClass a;
...
a = MyClass();
I use this pattern for resetting std::stack instances, as the stack adaptor does
not provide a clear function.
Technically it is bad practice to call constructors or destructors explicitly.
The delete keyword ends up calling them when you use it. Same goes for new with constructors.
I'm sorry but that code makes me want to tear my hair out. You should be doing it like this:
Allocate a new instance of an object
AnObject* anObject = new AnObject();
Delete an instance of an object
delete anObject;
NEVER do this:
anObject->~AnObject(); // My step 1.
free(anObject)
If you must "reset" an object, either create a method which clears all the instance variables inside, or what I would recommend you do is Delete the object and allocate yourself a new one.
"It is the core of the language?"
That means nothing. Perl has about six ways to write a for loop. Just because you CAN do things in a language because they are supported does mean you should use them. Heck I could write all my code using for switch statements because the "Core" of the language supports them. Doesn't make it a good idea.
Why are you using malloc when you clearly don't have to. Malloc is a C method.
New and Delete are your friends in C++
"Resetting" an Object
myObject.Reset();
There you go. This way saves you from needlessly allocating and deallocating memory in a dangerous fashion. Write your Reset() method to clear the value of all objects inside your class.
You cannot call the constructor in the manner indicated by you. Instead, you can do so using placement-new (like your code also indicates):
new (anObject) AnObject();
This code is guaranteed to be well-defined if the memory location is still available – as it should be in your case.
(I've deleted the part about whether this is debatable code or not – it's well-defined. Full stop.)
By the way, Brock is right: how the implementation of delete isn't fixed – it is not the same as calling the destructor, followed by free. Always pair calls of new and delete, never mix one with the other: that's undefined.
Yes, what you are doing is valid most of the time. [basic.life]p8 says:
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:
the storage for the new object exactly overlays the storage location which the original object occupied, and
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
neither the original object nor the new object is a potentially-overlapping subobject ([intro.object]).
So it is legal if you don't have a const or reference member.
If you don't have this guarantee, you need to use std::launder or use the pointer returned by placement new (like you're doing anyways) if you want to use the new object:
// no const/ref members
anObject->~AnObject(); // destroy object
new (anObject) AnObject(); // create new object in same storage, ok
anObject->f(); // ok
// const/ref members
anObject->~AnObject();
auto newObject = new (anObject) AnObject();
anObject->f(); // UB
newObject->f(); // ok
std::launder(anObject)->f(); // ok
Note that they're not malloc and free that are used, but operator new and operator delete. Also, unlike your code, by using new you're guaranteeing exception safety. The nearly equivalent code would be the following.
AnObject* anObject = ::operator new(sizeof(AnObject));
try
{
anObject = new (anObject) AnObject();
}
catch (...)
{
::operator delete(anObject);
throw;
}
anObject->~AnObject();
::operator delete(anObject)
The reset you're proposing is valid, but not idiomatic. It's difficult to get right and as such is generally frowned upon and discouraged.
Why not reset using the operator=()? This is not debatable and by far more readable.
A a;
//do something that changes the state of a
a = A(); // reset the thing
You can't call the constructor like that, but there's nothing wrong with reusing the memory and calling placement new, as long you don't delete or free (deallocate) the memory. I must say reseting an object like this is a little sketchy. I would write an object to be explicitly resetable, or write a swap method and use that to reset it.
E.g.
anObject.swap( AnObject() ); // swap with "clean" object
If your object has sensible assignment semantics (and correct operator=), then *anObject = AnObject() makes more sense, and is easier to understand.
It is far better just to add something like a Reset() method to your object rather than play with placement new's.
You are exploiting the placement new feature which is intended to allow you to control where an object is allocated. This is typically only an issue if your hardware has "special" memory like a flash chip. IF you want to put some objects in the flash chip, you can use this technique. The reason that it allows you to explicitly call the destructor is that YOU are now in control of the memory, so the C++ compiler doesn't know how to do the deallocation part of the delete.
It is not saving you much code either, with a reset method, you will have to set the members to their starting values. malloc() doesn't do that so you are going to have to write that code in the constructor anyway. Just make a function that sets your members to the starting values, call it Reset() call it from the constructor and also from anywhere else you need.

Do you call delete in destructor in C++?

Let say you have a class like this
class Level
{
public:
Level(std::string);
~Level();
private:
Bitmap* map;
}
and in the class you had this
Level::Level(std::string)
{
map = new Bitmap(path);
}
Was wondering do can you call
Level::~Level()
{
delete map;
}
As I was worried about if the class goes out of scope and I haven't deleted map. Then, wouldn't that cause a memory leak. Do I have to manually call to delete map. As I get crash if I call delete in the constructor in my program.
Like I could add a method to Level called say destroy map where I delete map. But, was wondering why I can't add delete into the destructor.
When the Level object goes out of scope, its destructor will be called, so deallocation of memory is useful because that memory is no longer needed. You can also use a unique_ptr, whereby memory-deallocation performed automatically.
This is why destructors stand for. Destructor is explicitly called when your object goes out of scope (memory residing on the stack objects) or when delete is called ( for dynamically allocated objects), so that the memory the object kept would be released. If you want to release member objects memory when destroyed, you can call the destructors of each object using delete (or delete[] for arrays). It is better that you use smart pointers, to avoid unintentional memory leaks and to ensure the memory is freed correctly in all cases, as they use RAII concept (RAII and smart pointers in C++).
Answers already have pointed out that you can trust your destructor to be called when your object goes out of scope. I won't reiterate that. I just wanted to point out that there is no need to allocate your Bitmap with new (unless you were using custom memory allocators, which is not the case here). You can construct it with an initialiser list:
class Level
{
public:
Level(std::string);
private:
Bitmap map;
};
Level::Level(std::string)
: map(path)
{
}
Now it has automatic scope and you don't have to worry about your destructor.
That's basically right.
However:
You need to make sure you create a copy constructor and assignment operator too, if you are managing memory this way. (That's where your crash comes from.)
An alternative, the best way, is to use RAII and store not a raw pointer but a scoped or automatic pointer. Or even just a directly encapsulated object! Then you don't need the delete at all.
As I was worried about if the class goes out of scope and I haven't deleted map. Then, wouldn't that cause a memory leak.
You're right - you should delete map exactly as your code does. But, you should also make your object non-copyable (derive from boost or C++11 noncopyable base classes, or add a private declaration (with no definition/implementation) of the operator= copy assignment and copy constructor. Otherwise, if you (deliberately or accidentally or incidentally - e.g. when storing your object in a container that sometimes copies it around, such as a std::vector) copy your object, then the first copy destructored will delete the map, any other copy that tries to use it will likely crash, and any other copy's destructor that also tries to delete it will also have undefined behaviour.
Do I have to manually call to delete map.
Yes, in your code you do.
A better alternative is to use a smart pointer whose own destructor will delete the pointed-to object.
As I get crash if I call delete in the constructor in my program.
Well, if you call delete after the new, then the constructor won't crash, but you wouldn't have a map object to use after the constructor returns, and if you then try to delete it again in the destructor the you get undefined behaviour which may well manifest as a crash.
If you want to delete the map earlier than the destructor sometimes, you can set the pointer to NULL so that a future delete will do nothing safely. You should then check for NULL before trying to use the map.
Like I could add a method to Level called say destroy map where I delete map. But, was wondering why I can't add delete into the destructor.
As above, you can have destroy_map, but it must coordinate with the destructor.
When there's no compelling reason to do otherwise, it's better to make the map member data, not storing it by reference. When a pointer is useful, use a smart pointer if at all possible. If you want to implement explicit manual memory management, be wary of the issues above.
This is an unusual way to do it. Normally, an object's lifetime is determined by factors outside of the object.
But in fact MFC used to (still does?) do exactly this when a Window is being destroyed. (In response to WM_NCDESTROY, I believe.) This ensures you don't have the Window instances leaking memory after the window is gone.
So I would say it is valid in some cases. You might call it class suicide!

Is it possible to delete an object in c++ without calling the destructor?

I have an object with some pointers inside of it. The destructor calls delete on these pointers. But sometimes I want to delete them, and sometimes I don't. So I'd like to be able to delete the object without calling the destructor. Is this possible?
Edit: I realize this is an AWFUL idea that no one should ever do. Nonetheless, I want to do it because it will make some internal functions much easier to write.
The delete operator does two things to the object you pass it:
calls the appropriate destructor.
calls the deallocation function, operator delete.
So deleting an object without calling a destructor means you want to simply call operator delete on the object:
Foo *f = new Foo;
operator delete(f);
operator delete is a normal function call and the usual name lookup and overload resolution is done. However the delete operator has its own rules for finding the correct operator delete. For example the delete operator will look for member operator delete functions that the usual name lookup and overload resolution does not find. That means that you need to make sure you're calling the right function when you manually use operator delete.
As you say, using operator delete directly is an awful idea. Failing to call the destructor breaks RAII, resulting in resource leaks. It can even lead to undefined behavior. Also, you'll have to take on the responsibility of writing exception safe code without RAII, which is exceptionally hard. You're almost guaranteed to get it wrong.
You can set the pointers to NULL, then the destructor will not delete them.
struct WithPointers
{
int* ptr1;
int* ptr2;
WithPointers(): ptr1(NULL), ptr2(NULL) {}
~WithPointers()
{
delete ptr1;
delete ptr2;
}
}
...
WithPointers* object1 = new WithPointers;
WithPointers* object2 = new WithPointers;
object1->ptr1 = new int(11);
object1->ptr2 = new int(12);
object2->ptr1 = new int(999);
object2->ptr2 = new int(22);
...
int* pointer_to_999 = object2->ptr1;
object2->ptr1 = NULL;
delete object1;
delete object2; // the number 999 is not deleted now!
// Work with the number 999
delete pointer_to_999; // please remember to delete it at the end!
Eww! Yes, it's possible, no I wouldn't do it. Have the objects that need variable lifetime be controlled via a shared pointer or some other reference counted object instead. Cleaner to work with C++ than breaking some of its internal tenants...
Whatever you're actually trying to do, there is a problem with your code.
If you don't want to delete the sub-objects, just use a boolean flag that you will set before deleting the object and that will be taken into account by the destructor.
But honestly, you should be using smart pointers instead of naked pointers (and in your very case, it looks like shared pointers are what you need).
Write a method that you can call before calling the destructor. The method will flip a member boolean. When the destuctor is called, it will check that boolean member and destroy the pointer if it is true, and keep it if it is false.
I wouldn't recommend doing this. Better for the class to not take responsibility for deleting the pointer.
Yes, this is possible. std::vector does this, in that it allocates buffers with space for objects, then conditionally constructs them (in-place) and destroys them, managing the memory independently of the object lifetime.
In C++11, I'd use a union of your type and a small type with trivial constructors/destructors to indicate a memory location that can fit your type, but doesn't have to have that type in it. External to that you have to track if the object is actually there. Creating the item consists of using placement new, and destroying it consists of manually calling the destructor.
The buffer of the union objects, be it N objects or 1, would be managed completely independently. The default constructor of the union would either construct nothing, or construct the trivial type (in which case you might want to destroy that trivial type).
However, odds are that the real answer to your question is "don't do that". And if you do that, you wrap the pointers in a class whose only job is handling the above mess. Classes of that type (whose job is to manage a pointer's lifetime and pointer-like properties) are called "smart pointers".
As others have suggested, the correct way to solve this problem isn't to NOT call the destructor [you only need to add something like std::string or std::vector to your object, and all of a sudden you have a memory leak]. The correct way is to either not let your object own those other objects at all (e.g. delete them separately before/after the object is deleted), or have a method with which the object knows whether to delete the pointers or not.