If I have the following struct
struct test
{
char *x;
std::string y;
};
And I initialize with
test *t = new test();
That should value-initialize the object and do the following based on the standard:
if T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;
struct test has a non-trivial constructor, this can be checked with:
static_assert(std::is_trivially_constructible<test>::value, "test is not is_trivially_constructible");`)
Does the standard imply that my test object should always be zero-initialized in the case of value-initialization, and then subsequently default-initialized?
And should I be able to reliably assume that after doing test *t = new test() if I immediately check t->x == nullptr, that should be true because char *x (a pointer / scalar type) should get zero-initialized during value-initialization of test.
I ask because Coverity gives a Type: Uninitialized pointer read (UNINIT) warning because it reports the following if you try do something like if (t->x) after value-intialization:
Assigning: "t" = "new test", which is allocated but not initialized.
Is Coverity misinterpreting the standard as "value-initialization if trivial constructor OR default-initialization if non-trivial constructor"? If I remove the std::string y; member so that test has a trivial-default-constructor, Coverity no longer has a warning and assumes the char *x member is zero-initialized.
For what it's worth, I'm just using g++ -O3 -std=c++17 to compile and I have not been able to create an actual scenario where zero-intialization doesn't happen for my test object.
()initializer which makes all the difference here. (That it makes all the difference seems very fragile btw. It could be made much safer without losing anything by just writingchar *x{};in the class definition.)