Search code examples
c++undefined-behaviorobject-lifetimeplacement-new

Can value of buffer change after destructor executes


Code:

#include <cstdio>
#include <new>

struct Foo {
  char ch;
  ~Foo() { ++ch; }
};

int main() {
  static_assert(sizeof(Foo) == 1);
  char buffer;
  auto const* pc = new (&buffer) Foo{42};
  
  // Change value using only the const pointer
  std::printf("%d\n", +buffer);
  pc->~Foo();
  std::printf("%d\n", +buffer);
}

godbolt

I am not causing any UB as far as I can tell, but GCC and Clang disagree on the result. I think the output should obviously be "42 43". That is the case for Clang, but GCC thinks the output is "42 0". How is that possible? Who zeros out the buffer? Am I missing something?


Solution

  • In your final line, the lvalue buffer doesn't access any object.

    The char object that was there initially had its lifetime ended by reusing its storage for a Foo. The Foo had its lifetime ended by invoking the destructor. And no one created any object in the storage after that.

    lvalue-to-rvalue conversion (which is what +buffer does, but passing buffer as an argument to a variadic function would too) is not permitted where no object exists.