Emptying a C ++ Object

Often I add the Empty method to my C ++ objects to clear the internal state using code similar to the following.

 class Foo { private: int n_; std::string str_; public: Foo() : n_(1234), str_("Hello, world!") { } void Empty() { *this = Foo(); } }; 

This seems to be better than duplicating the code in the constructor, but I wondered if *this = Foo() common when you need to clear an object? Are there any problems with this expectation to bite me from behind? Are there any other ways to achieve this kind of thing?

+4
source share
10 answers

I would call the constructor instead of my function:

 class Foo { private: int n_; std::string str_; public: Foo() { Reset(); } void Reset() { n_ = 1234; str_ = "Hello, world!"; } }; 

Yes, you first initialize the string as an empty string, and then do the assignment, but that is much clearer.

+11
source

Potential problems? How do you know that this is really foo?

+9
source

What you do with this empty method is essentially the same as manually assigning a newly constructed object to a variable (the thing that the Empty function does).

Personally, I delete the Empty method and replace all its use as follows:

 // let say, that you have variables foo and pfoo - they are properly initialized. Foo foo, *pfoo; // replace line "foo.Empty()" with: foo = Foo(); // replace line "pfoo->Empty()" with: delete pfoo; pfoo = new Foo(); // or *pfoo = Foo(); 

I really don't see the benefits of using this empty method. He hides what really happens with the object on the witch, which he named, and this is not the best choice.

If the caller really wants a clean object, he will have no problem constructing the object itself.

+6
source

Also, consider making objects immutable, i.e. when built, they cannot be changed. This can get rid of unforeseen side effects in many scenarios.

+5
source

There is something more common than what you suggested. using swap.

Basically you do something like this:

 T().swap(*this); 

since many standard containers (all STL containers?) have a constant method of time folding, this is a good and easy way to clean the container and ensure it is empty.

Similarly, this is a good way to “shrink to fit” the container, but using the copy constructor instead of the default constructor.

+4
source

consider using the new placement:

 void Empty() { this->~Foo(); new (this) Foo(); } 

Your code calls operator = , which can lead to all kinds of side effects.

EDIT in response to comments. - This code is definitely clearly defined, the standard clearly allows it. I will send the paragraph later if I find the time. About delete - of course. I meant ~Foo() , that was supervision. And yes, Rob is right; destruction of the object is actually necessary here to call the string destructor.

+2
source

This can be a potential source of memory leak if you have dynamically allocated memory in the constructor.

+2
source

Here is how I do it:

 class Foo { private: int n_; std::string str_; public: Foo() : n_(1234), str_("Hello, world!") { } void Empty() { Foo f; swap(f); } void swap(Foo & other) { std::swap(n_, other.n_); swap(str_, other.str_); } }; void swap(Foo & one, Foo & other) { one.swap(other); } 

Place the swap function in the same namespaces as the Foo class. The dependent search argument finds this when users make a call to exchange in order to exchange two Foo. You can implement operator= using your swap function.

+2
source

This seems to be better than duplicating the code in the constructor, but I wondered if * this = Foo () is the usual approach if you want to clear the object?

Deleting an object is not so important: most often an object (possibly even an immutable object) is created and contains real data or not created.

Most common type reset will be containers ... but now you won’t write your own container classes, could you.

Are there any problems with this expectation to bite me on the back?

Yes:

  • If it's not really Foo , but instead DerivedFoo
  • If the assignment operator Foo does not exist or it is erroneous (for example, if it is not defined and the default operator is not good, for example, because of the data element there is a bare pointer).

Are there any other ways to achieve this kind of thing?

Yes, maybe a free function would be better (avoid both problems):

 template<class T> void reconstruct(T* p) { p->~T(); new (p) T(); } 
+1
source

Yes, this is inefficient in terms of performance (creating another foo object instead of working in place), and it will bite you if you allocate memory in the constructor with an unpleasant memory leak.

Make it safer in terms of memory to call this-> delete and this = new foo () - but it will be SLOW.

if you want to be superfast, create a static field of an empty object and memcpy it in Reset.

if you just want to quickly assign properties one by one.

if you want to maintain a reasonable style without duplicating the Reset call from Ctor, as Ates Goral suggested, but you will lose the faster construct with the default parameters.

-2
source

All Articles