0

If I can a parameter pack for the constructor arguments when I create a new object and I don't provide any constructor arguments then the result will be: new T(); which will value-initialize the object if it doesn't have a user-provided constructor. How do I stop this from happening?

template <typename T>
struct Foo
{
    template <typename ... ConstructorArgs>
    static void create(ConstructorArgs ... constructorArgs)
    {
        T* ptr = new T(constructorArgs ...);
        T* ptr2 = new T;
        std::cout << *ptr; // It seems it value-initialized (zero-initialized) it
        std::cout << *ptr2; // Default initialized it

    }

};
int main()
{
    Foo<int>::create();
}
Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • You can't. If the goal is to do the memory allocation without initializing the object you will have to use placement new. – super Apr 08 '21 at 04:40
  • @super Placement new still results in value-init, char buf[4]; new (buf) T(constructorArgs...); still value_initialized it to 0. – Zebrafish Apr 08 '21 at 04:44
  • Yes, the point is that it separates allocation and initialization into two steps. So like I said above... *If the goal is to do the memory allocation without initializing the object*. – super Apr 08 '21 at 04:49
  • Also, how is the template part here relevant to the question? – super Apr 08 '21 at 04:52
  • Because it's a template that can either take constructor arguments or not. Otherwise I would have done new T; instead of new T(constructorArgs...); I wanted it to handle both cases. – Zebrafish Apr 08 '21 at 04:57
  • Ok, I'm still a bit confused then. Since this would only ever be relevant for built-in types... why is it a concern at all? – super Apr 08 '21 at 05:08
  • 1
    @super If I have a plain struct PlainStruct { int a, char b; }; and I pass no arguments to Foo::create(); it'll value-initialize it, meaning zero-initialize members 'a' and 'b'. I posted an answer, it works with sizeof parameter pack. – Zebrafish Apr 08 '21 at 05:19

1 Answers1

1

This is working with constexpr sizeof... (ConstructorArgs), but I'd also like to know if there's a better way.

template <typename T>
struct Foo
{
    template <typename ... ConstructorArgs>
    static void create(ConstructorArgs ... constructorArgs)
    {
        T* ptr;
        if constexpr (sizeof ... (ConstructorArgs) == 0)
            ptr = new T;
        else
            ptr = new T(constructorArgs ...);
    }

};
int main()
{
    Foo<int>::create(); // Default initializes
    Foo<int>::create(0); // Value/Zero initialized

}

It works with new and placement new, and with a lvalue stack variable, but not a temporary, ie., T{ }, as those braces will value-initialize if T has no user-defined constructor.

Zebrafish
  • 11,682
  • 3
  • 43
  • 119