15

I will keep it short and just show you a code example:

class myClass
{
public:
  myClass();
  int a;
  int b;
  int c;
}

// In the myClass.cpp or whatever
myClass::myClass( )
{
 a = 0;
 b = 0;
 c = 0;
}

Okay. If I know have an instance of myClass and set some random garbage to a, b and c.

  • What is the best way to reset them all to the state after the class constructor was called, so: 0, 0 and 0?

I came up with this way:

myClass emptyInstance;
myUsedInstance = emptyInstance; // Ewww.. code smell?

Or..

myUsedInstance.a = 0; myUsedInstance.c = 0; myUsedInstance.c = 0; 
  • I think you know what I want, is there any better way to achieve this?
Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Oper
  • 153
  • 1
  • 1
  • 4

5 Answers5

26
myUsedInstance = myClass();

C++11 is very efficient if you use this form; the move assignment operator will take care of manually cleaning each member.

Fabio A. Correa
  • 1,968
  • 1
  • 17
  • 26
Goz
  • 61,365
  • 24
  • 124
  • 204
  • 4
    Now, what if I want to do this from inside? `*this = MyClass()`? – Xeverous Feb 03 '18 at 12:55
  • Not sure, I'm sure it will work in pretty much every situation. However I'm not sure whether it is "undefined behaviour" or not – Goz Mar 21 '18 at 19:24
  • @sameerchaudhari It compiles and works, but I'm not sure whether this is well-defined by the papers or compilers just happen to understand it – Xeverous Mar 22 '18 at 13:41
7

You can implement clear as a generic function for any swappable type. (A type being swappable is common and done implicitly in C++0x with a move constructor. If you have a copy constructor and assignment operator that behave appropriately, then your type is automatically swappable in current C++. You can customize swapping for your types easily, too.)

template<class C>
C& clear(C& container) {
  C empty;
  using std::swap;
  swap(empty, container);
  return container;
}

This requires the least work from you, even though it may appear slightly more complicated, because it only has to be done once and then works just about everywhere. It uses the empty-swap idiom to account for classes (such as std::vector) which don't clear everything on assignment.


If you have seen that the swap is a performance bottleneck (which would be rare), specialize it (without having to change any use of clear!) in myClass's header:

template<>
myClass& clear<myClass>(myClass& container) {
  container = myClass();
  return container;
}

If myClass is a template, you cannot partially specialize clear, but you can overload it (again in the class header):

template<class T>
myClass<T>& clear(myClass<T>& container) {
  container = myClass<T>();
  return container;
}

The reason to define such specialization or overload in myClass's header is to make it easy to avoid violating the ODR by having them available in one place and not in another. (I.e. they are always available if myClass is available.)

Community
  • 1
  • 1
  • You might want to emphasize why you suggest this, rather than just relying on the default constructor like others suggested. – Dennis Zickefoose Apr 18 '10 at 22:26
  • Its quite good as written. I mostly meant this line: "It uses the empty-swap idiom to account for classes (such as std::vector) which don't clear everything on assignment." Without those special cases, there's not much benefit to the whole setup. – Dennis Zickefoose Apr 19 '10 at 00:03
4

Just assign to a default-constructed class, like you have. Just use a temporary, though:

struct foo
{
    int a, b, c;

    foo() :
    a(), b(), c()
    {} // use initializer lists
};

foo f;
f.a = f.b =f.c = 1;

f = foo(); // reset
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 2
    @Oper It's the standard C++ way of doing what you asked - any reasonably experienced C++ programmer will recognise the meme. –  Apr 18 '10 at 21:40
0

You may want to consider using placement new. This will allow you to use the same memory but call the constructor again.

Don't forget to call the destructor before using placement new, however.

ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
  • 7
    In other words, you may not want to consider this. I would only do this under very exceptional circumstances, and even then think twice - a = A() is almost always the best bet. –  Apr 18 '10 at 21:38
  • 1
    Thanks — all other solutions assume that you have a copy constructor. – Clément Jan 04 '21 at 19:54
-2

Well, there is a much much more elegant way: Create a vector of your classes with single element and update that element calling the constructor:

std::vector<your_class> YourClasses;
YourClasses.resize(1);
YourClasses[0] = YourClass(...);

YourClass &y_c = *(&YourClasses[0]);
// do whatever you do with y_c
// and then if you want to re-initialize, do this
YourClasses[0] = YourClass(...);
// and voilla, continue working with resetted y_c