0

Let's say I have an object I would like to initialize to 0 in the constructor. Every bit that the instanced object occupies should be 0 without exception, including all non-POD members, ignoring their personal default constructors completely.

Is this possible in C++? And if so, is there a way this can be done that is at least as fast as initializing each member to 0 through an initialization list (when allowed)?

(there's obvious pitfalls but I'm curious; please assume I have a not-awful reason!)

Anne Quinn
  • 12,609
  • 8
  • 54
  • 101
  • 1
    What about `memset(this, 0, sizeof(*this));` ? – GMichael May 25 '16 at 04:30
  • @Michael: That will run after the object's constructor has run. – Cornstalks May 25 '16 at 04:31
  • 1
    "optimization" means making correct code run faster, not breaking the code. For a non-POD the only correct way to create one is to invoke its constructor or use aggregate initialization (if it is an aggregate) – M.M May 25 '16 at 04:34
  • 1
    Given some type `T`, I might suggest using [`std::aligned_storage::type`](http://en.cppreference.com/w/cpp/types/aligned_storage) which you can use create a variable that you can reinterpret as a `T`. The aligned storage can be initialized to all zeros with normal value initialization, which is about as efficient as you'll get. Note that if `T` has a nontrivial constructor/destructor you'll have to manually manage that, and if you aren't careful you'll invoke undefined behavior. – Cornstalks May 25 '16 at 04:38
  • @Cornstalks UB is unavoidable that way, storage with no objects cannot be treated as if it contained objects; and objects can only be created in such storage by using placement new. – M.M May 25 '16 at 04:52
  • 1
    You are using a wrong language for the job. – n. m. could be an AI May 25 '16 at 04:55
  • @M.M: UB is avoidable if the aligned storage isn't accessed as a `T` until the placement new has taken place. Yes, this approach can very easily lead to UB, but it's not completely unavoidable. – Cornstalks May 25 '16 at 05:02
  • The storage can't be accessed as anything before the placement new ; and the new will do the same thing that just declaring an object would have done (and OP seems to want to avoid) – M.M May 25 '16 at 05:11
  • @M.M: The storage can be accessed as a `unsigned char`, perhaps as part of a `memcpy`. [The following is valid](https://godbolt.org/g/eaffNj) (not super useful, but not UB either). – Cornstalks May 25 '16 at 05:26
  • @Cornstalks IMO that example is UB, the memcpy reads out of bounds of any object. But this is a bit problematic to discuss because the C++ standard does not properly define the behaviour of `memcpy` in C++; it says it is "the same as C99 memcpy", but C has a different object model to C++ – M.M May 25 '16 at 05:35
  • @M.M: Why do you say it reads outside of the bounds of any object? The standard says "The member typedef `type` shall be a POD type..." (in Table 57). The aligned storage clearly is a valid object (we even know it has a POD type), and that is the object that is being read. – Cornstalks May 25 '16 at 05:47
  • @Cornstalks good point, I was equating it to malloc but of course it is an object. So this is a sort of solution although it seems like OP probably di want to treat it as a `T` – M.M May 25 '16 at 06:46
  • You can leverage the fact that static instances are zero initialised: http://stackoverflow.com/a/38103250/3223828 – Stuart Gillibrand Jun 29 '16 at 15:23

1 Answers1

1

There is no "magic" syntax to achieves this.

If the class has no virtual table, you could use memset(this, 0, sizeof(* this)), but it is not recommended.

You could try to play with offsetof to pinpoint the address of the first member, and erase from there on. This is a bit better than simply memseting the whole thing, but it is still making me uncomfortable:

// Example non-POD type.
class B
{
public:
    B() : b(0xDEADBEEF) {}
    int b;
};

class Monstrosity
{
public:
    Monstrosity()
    {
        size_t offset = offsetof(Monstrosity, a);
        uint8_t *eraseStart = (uint8_t *)this + offset;
        memset(eraseStart, 0, sizeof(Monstrosity) - offset);
    }

    virtual int foo() { return 0; }

    int a;
    B b;
};

If any if your members has a virtual table, you're practically screwed.

Gilad Naaman
  • 6,390
  • 15
  • 52
  • 82