1

In plain C it's common to reset a struct after instantiation:

struct MyClass obj;
memset( &obj, 0, sizeof(struct MyClass) );

This is convenient - especially when using an object oriented paradigm, since all members are guaranteed to be reset to null etc. no matter how many members are added over time.

I'm looking for a way to do the same in C++. Obviously you can't simply reset the memory since the vtable is part of it. Also, in my particular case I can't use templates.

One solution I've seen is to declare a struct with all members, which you in turn can reset in a single blow:

class MyClass{

  MyClass(){ memset(&m, 0, sizeof(m)); }

  struct{
     int member;
  } m;
};

I'm however not very fond of this solution.

I guess "hacks" are available, and if you know one, please also say something about the risks of using it, e.g. if it can differ between compilers etc.

Thanks

sharkin
  • 12,162
  • 24
  • 86
  • 122
  • 2
    Here's one clean way: http://stackoverflow.com/questions/3930841/is-there-a-way-to-make-a-c-struct-value-initialize-all-pod-member-variables/3931028#3931028 – sharptooth Jan 21 '11 at 08:59
  • @sharptooth: Nice, however I can't use templates in this case. I've updated the question. – sharkin Jan 21 '11 at 09:26
  • @sharkin: Why can't you use templates? – sharptooth Jan 21 '11 at 09:27
  • @sharptooth: Due to coding standard restrictions. – sharkin Jan 21 '11 at 10:51
  • @sharkin: I believe this is the time when your coding restrictions prevent you from writing good code and the solution is to refine the restrictions. – sharptooth Jan 21 '11 at 10:56
  • You could omit the constructor and get the same effect with `MyClass m = MyClass();`. If you omit the right-hand part, POD members would remain uninitialized as in the C example. - This won't work, though, if you have other user-defined constructors. – UncleBens Jan 21 '11 at 16:07
  • Here are some other ways: http://stackoverflow.com/a/38103250/3223828 – Stuart Gillibrand Jun 29 '16 at 18:23

2 Answers2

2

If you want to assure that you allocated a memory block with zeros you can use a placement new operator:

size_t sz = sizeof(MyClass);
char *buf  = new char[sz];
memset(buf, 0, sz);
MyClass* instance = new (buf) MyClass;
sharkin
  • 12,162
  • 24
  • 86
  • 122
Vladimir
  • 1,781
  • 13
  • 12
  • That't ridiculous. If you want to pre-fill the block with zeroes you just overload `operator new` for that class and make it do the pre-fill. – sharptooth Jan 21 '11 at 09:26
  • @sharptooth Don't be a puppy; what is the right solution depends on its intentions. He really can overload operator new, but in some cases mentioned solution is acceptable and much faster. Or you think that (for example) guys in IBM advise ridiculous things :) http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc05cplr199.htm – Vladimir Jan 21 '11 at 09:38
  • @Vladimir: First, the have a memory leak in the last snippet. Second, they don't advise what you suggest, their example is just illustrational. – sharptooth Jan 21 '11 at 09:44
  • Btw even guys at Microsoft do very stupid things once in a while : http://blogs.msdn.com/b/aszego/archive/2010/05/12/override-atlthrow-with-care.aspx – sharptooth Jan 21 '11 at 09:51
  • @sharptooth: You pointed to a blog :) But, OK - an illustrative example I pointed to can be used in same cases. We don't know if guy who asked a question wants to use it on the same way or not. And finally, if he wants to use it just once, it is more appropriate to use placement new, than to overload operator new. As I said - the right solution depends on circumstances. You cannot insist that one solution is better than other if you don't know a backdrop how it will be used. Regards. – Vladimir Jan 21 '11 at 12:24
  • @Vladimir:Yeap, fair enough. Just worth reminding that the object will have to be deallocated by casting the pointer to `char*` type, then calling `delete[]`. – sharptooth Jan 21 '11 at 12:39
  • I like this solution, even though the ownership part tempts you to wrap up things in macros. However, an additional advantage is that this solution blends well with memory pools, in which case the ownership also becomes less of an issue. Thanks. – sharkin Jan 24 '11 at 23:49
0

Not to be a spoilsport, but why don't you simply add an initializer list for the members that need a defined value for the object to be valid, and let the compiler figure out the ideal way to initialize the object.

Depending on the type of the object, this can save quite an amount of code size and/or time, plus it is safe even if the "empty" representation for a certain type is not all-zeros. For example, I have hacked a compiler once that the NULL pointer is 0x02000000, and converting between integers and pointers XORs with that value; your program would then initialize any pointer members to non-NULL values.

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • I'm not really sure what you mean (code example perhaps?), but it sounds like your proposed solution means that I have to maintain the initializer list every time I add a member. This is the main thing I'd like to avoid. Please clarify if I'm wrong. – sharkin Jan 21 '11 at 10:50
  • You do have to maintain the initializer list, however if the member does not affect the state of the object if uninitialized, just leave it out. For example, if you have a buffer class, you'd initialize the pointers that track valid data, but leave the memory area for the buffer itself uninitialized. – Simon Richter Jan 21 '11 at 12:38
  • The NULL pointer issue I mentioned is that `char *foo = 0;` would write 0x02000000 into the memory representing `foo` on my system, because we want the CPU to trap if that pointer is ever dereferenced. Your code would initialize the memory to 0x00000000, which would not compare equal to the NULL pointer (so `(bool)foo` would be `true`), hence the program would misbehave assuming that the pointer is valid. – Simon Richter Jan 21 '11 at 12:42