Consider the following code, where T is a member pointer:
#include <cassert>
struct Foo { double v = 0; };
int main()
{
using T = double Foo::*;
T p1 = nullptr;
T p2 = T();
T p3{};
T * pp4 = new T();
T * pp5 = new T{};
assert(p1 == p2);
assert(p1 == p3);
assert(p1 == *pp4); // Fails on MSVC
assert(p1 == *pp5); // Fails on MSVC
delete pp4;
delete pp5;
}
clang and gcc compile and run this without problems (live on godbolt). However, MSVC (e.g. in version 19.35, but also others) does not: It compiles, but the asserts for pp4 and pp5 fail. If I understand the cppreference for value initialization correctly, pp4 and pp5 should be zero initialized, where in turn I would expect the resulting value to compare equal to nullptr. Printing the values to cout shows that all values are 0, except for pp4 and pp5 which are 1. Is this a MSVC bug, or is my understanding of member pointers and reading the cppreference wrong?
Background: Of course, having dynamically allocated member pointers is rather uncommon. I stumbled upon this while testing whether my tiny::optional can cope with member pointers (optional<double Foo::*>). Internally, the library uses placement new to construct the value, which shows the same issue.
MSVC is not standard conformant here because
T = double Foo::*is a scalar type andnew T()is value initialization which will result in zero initialization in this case.This can be seen from value initialization:
This means that zero initialization will be performed here.
Next, from zero initialization:
This means that the effect is the same as if we were to write
T * pp4 = 0;andT * pp5 = 0. Thus,pp4andpp5both should compare equal tonullptr.