Destroy and Then Construct New Object Using the Same Variable

Destroy and then construct new object using the same variable

I think the only way to make this really safe to use is to require the called constructor to be noexcept, for example by adding a static_assert:

static_assert(noexcept(T(22, Brown, true)), "The constructor must be noexcept for inplace reconstruction");
T x(31, Blue, false);
x.~T();
::new (&x) T(22, Brown, true);

Of course this will only work for C++11.

Destroy old instance of object and create new one in a loop

You do not need to set ob and ob2 to null.

In your code above after each iteration of your for-loop you can no longer access the ob and ob2 objects from the previous iteration. This means that they will be garbage collected eventually.

However, if they implement IDisposable you should dispose them before the end of each iteration.

What happens to the old object if you set a variable equal to a new object?

What you need to understand is that there's a lot of "implicit" code generated by the compiler that you, as a novice, don't know about. We'll use your code for class X as a direct example:

class X {
int n;
public: //You didn't include this, but this won't work at all unless your constructors are public
X() {n = 0;}
X(int _n) {n = _n;}
};

Before the code gets turned into Object Code, but after your compiler gets ahold of your class definition, it transforms your class into something that looks (roughly) like this:

class X {
int n;
public:
X() {n = 0;} //Default-Constructor
X(int _n) {n = _n;} //Other Constructor
//GENERATED BY COMPILER
X(X const& x) {n = x.n;} //Copy-Constructor
X(X && x) {n = x.n;} //Move-Constructor
X & operator=(X const& x) {n = x.n; return *this;} //Copy-Assignment
X & operator=(X && x) {n = x.n; return *this;} //Move-Assignment
~X() noexcept {} //Destructor
};

The rules for when these members are automatically created are not super-obvious (A good starting reference here), but for now, you can trust that in this case, that's exactly what happens.

So in your main function, let's go over what happens, with the specifics called attention to with comments:

int main() {
X a; //Default-Constructor called
a = X(7);//Other Constructor called, then Move-Assignment operator called,
//then Destructor called on temporary created by `X(7)`
a = X(12); //Same as previous line

return 0;
//Destructor called on `a`
}

We'll add a few more lines to show most (if not all) of the various permutations of these calls:

int main() {
X a; //Default-Constructor
X b = a; //Copy-Constructor (uses copy-elision to avoid calling Default + copy-assign)
X c(5); //Other Constructor
X d{7}; //Also Other Constructor
X e(); //Declares a function! Probably not what you intended!
X f{}; //Default-Constructor
X g = X(8); //Other Constructor (uses copy-elision to avoid calling Other + move-assign + Destructor)
X h = std::move(b); //Move-Constructor (uses copy-elision to avoid calling Default + move-assign)
b = c; //Copy-assignment
b = std::move(d); //Move-assignment
d = X{15}; //Other Constructor, then Move-Assignment, then Destructor on `X{15}`.
//e = f; //Will not compile because `e` is a function declaration!
return 0;
//Destructor on `h`
//Destructor on `g`
//Destructor on `f`
//Destructor will NOT be called on `e` because `e` was a function declaration,
//not an object, and thus has nothing to clean up!
//Destructor on `d`
//Destructor on `c`
//Destructor on `b`
//Destructor on `a`
}

That should cover the basics.

And most importantly, is there ever a chance of causing a memory leak by writing code like in the above?

As written, no. However, suppose your class did something like this instead:

class X {
int * ptr;
public:
X() {
ptr = new int{0};
}
};

Now, your code would leak, because every time an X was created, you'd have a pointer that never gets deleted.

To solve this, you need to make sure that A) The destructor properly cleans up the pointer, and B) that your copy/move constructors/operators are correct.

class X {
int * ptr;
public:
X() {
ptr = new int{0};
}
X(int val) {
ptr = new int{val};
}
X(X const& x) : X() {
*ptr = *(x.ptr);
}
X(X && x) : X() {
std::swap(ptr, x.ptr);
}
X & operator=(X const& x) {
*ptr = *(x.ptr);
return *this;
}
X & operator=(X && x) {
std::swap(ptr, x.ptr);
return *this;
}
~X() noexcept {
delete ptr;
}
};

This code will not leak memory if used as-is in either your main function or mine. But of course, it doesn't stop the leaks if you do something like this:

int main() {
X * ptr = new X{};
return 0;
//Whelp.
}

In general, if you never need to use pointers at all, it's recommended you use something like std::unique_ptr instead, as it gives most of this stuff for free.

int main() {
std::unique_ptr<X> ptr{new X{}};
return 0;
//Destructor called on *ptr
//`delete` called on ptr
}

And it's a good idea in your original class, with a caveat that, unless you explicitly change it, your class won't by copyable anymore (though it'll still be movable):

class X {
std::unique_ptr<int> ptr;
public:
X() {
ptr.reset(new int{0});
}
X(int val) {
ptr.reset(new int{val});
}
//X(X && x); //auto generated by compiler
//X & operator=(X && x); //auto generated by compiler
//~X() noexcept; //auto generated by compiler

//X(X const& x); //Deleted by compiler
//X & operator=(X const& x); //Deleted by compiler
};

We can see the changes in my previous version of main:

int main() {
X a; //Default-Constructor
//X b = a; //Was Copy-Constructor, no longer compiles
X c(5); //Other Constructor
X d{7}; //Also Other Constructor
X f{}; //Default-Constructor
X g = X(8); //Other Constructor (uses copy-elision to avoid calling Other + move-assign + Destructor)
X h = std::move(c); //Move-Constructor (uses copy-elision to avoid calling Default + move-assign)
//b = c; //Was Copy-assignment, no longer compiles
c = std::move(d); //Move-assignment
d = X{15}; //Other Constructor, then Move-Assignment, then Destructor on `X{15}`.
return 0;
//Destructor on `h`
//Destructor on `g`
//Destructor on `f`
//Destructor on `d`
//Destructor on `c`
//Destructor on `a`
}

If you want to use std::unique_ptr, but also want the resulting class to be copyable, you'll need to implement the copy constructor yourself using the techniques I discussed.

And that should be about it! Let me know if I missed anything.

Delete object and create again at the same memory place


what is the guarantee that the object will be created at the same
memory place?

There are no such guarantees whatsoever.

However, you will sometimes see the next object created in the same place in memory under certian circumstances. In particular, in a MSVC Debug build you might see this happen frequently. But you should never rely on this behavior. It will stop happening just when you think it is working perfectly, and it never guaranteed to happen.

If you do need to create an object in the same place in memory, there is a C++ mechanism for that, called "placement new." However I must warn you -- using this is a bit tricky because you have to establish a buffer first, then placement-new your object there, and then
explicitly call the destructor yourself before creating the next object. When you're done, you have to destroy the buffer. Not to mention alignment concerns, which complicates matters to a whole other level.

There are many opportunities for bugs and mistakes when using placement-new, the code can be difficult to maintain, and the times when you actually need this functionality is exceedingly rare in normal programming. As long as I've been doing C++ professionally, I could count the number of times I needed placement-new on one hand.

If you don't absolutely , positively know that you need placement-new, you don't need it.

Call destructor and then constructor (resetting an object)

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.

JavaScript: Create and destroy class instance through class method

No. JavaScript is automatically garbage collected; the object's memory will be reclaimed only if the GC decides to run and the object is eligible for collection.

Seeing as that will happen automatically as required, what would be the purpose of reclaiming the memory explicitly?

How can i destroy all the objects before creating new ones?

change Destroy(objInstance); to DestroyImmediately(objInstance); should work.

However, to remove and add new objects in update is not a good idea. you may try to maintain a object pool to add/remove a specific object, and only when many objects are removing/adding in one action, you should do the batch process.

How to destroy and create same gameobject in unity

Problems:

You are trying to access your monsters like this:

selectedMonster.GetComponent<Monster>()

It means if you have in your scene more than one GameObject of type Monster, Unity will not be sure which one you are referring to.

Also when you instantiate a monster, you use just

Instantiate(selectedMonster.GetComponent<Monsters>().Monster, new Vector3(Random.Range(1,8), Random.Range(1,8), -1), Quaternion.identity);

So you will not be able to distinguish one instance from another in your scene.

Solutions:

In case you wanted to continue with this approach, where you check if tileX and tileY of monster match with your Unit (which I assume is your hero or similar), you should have all monsters inside an array so you can iterate them all in a way you refer easily to the one you want to destroy.

You could try FindObjectsOfType and there pass your Monster type:

Monster [] monsters= FindObjectsOfType(typeof(Monster )) as Monster [];

Then you iterate

foreach (Monster thisMonster in monsters){
//check things here
}

Another option is to store the monsters in an array when you instantiate them

//Define as global variable a list of Monsters
List<GameObject> monsterList = new List<GameObject>();

//Then you instantiate then like
monsterList .add((GameObject)Instantiate(selectedMonster.GetComponent<Monsters>().Monster, new Vector3(Random.Range(1,8), Random.Range(1,8), -1), Quaternion.identity));

And you iterate them using the foreach as before

Better Solution (From my point of view)

However, since your main goal, correct me if I am wrong, is to detect when the position of a Unit match with the position of a monster, to later destroy that particular monster. I would use colliders instead. And in the GameObject you call Unit I would add a TriggerEnter. Since you use the TileX and TileY I suspect you are creating a 2D game, so it would be something like this:

void OnTriggerEnter2D(Collider2D other) {
Destroy(other.gameObject);
}

With this you destroy any monster that touches your "Unit" and you will not have reference problems.

Is it allowed to call destructor explicitly followed by placement new on a variable with fixed lifetime?

First, [basic.life]/8 clearly states that any pointers or references to the original foo shall refer to the new object you construct at foo in your case. In addition, the name foo will refer to the new object constructed there (also [basic.life]/8).

Second, you must ensure that there is an object of the original type the storage used for foo before exiting its scope; so if anything throws, you must catch it and terminate your program ([basic.life]/9).

Overall, this idea is often tempting, but almost always a horrible idea.

  • (8) 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:

    • (8.1) the storage for the new object exactly overlays the storage location which the original object occupied, and
    • (8.2) the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
    • (8.3) 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
    • (8.4) the original object was a most derived object (1.8) of type
      T and the new object is a most derived
      object of type T (that is, they are not base class subobjects).
  • (9) If a program ends the lifetime of an object of type T with static (3.7.1), thread (3.7.2), or automatic (3.7.3) storage duration and if T has a non-trivial destructor, the program must ensure that an object of the
    original type occupies that same storage location when the implicit destructor call takes place; otherwise the behavior of the program is undefined. This is true even if the block is exited with an exception.

There are reasons to manually run destructors and do placement new. Something as simple as operator= is not one of them, unless you are writing your own variant/any/vector or similar type.

If you really, really want to reassign an object, find a std::optional implementation, and create/destroy objects using that; it is careful, and you almost certainly won't be careful enough.



Related Topics



Leave a reply



Submit