5

Here on SO we have had a lot of questions about assignments to const fields and Undefined Behavior (UB). For example This accepted answer which says that is not possible to define a copy assignment operator for classes with const fields because of UB.

But I checked the current draft version of the C++ standard (N4861). The part which said it would be UB [basic.life.8] was:

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:...

the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and

Has now been replaced with:

o1 is not a complete const object, and

My interpretation is, that the following code now has no UB. Is it right? I ask this because in the sample, there is no cv qualified member - so it's still not clear for me.

#include <iostream>

struct C {
  const int i;
  void f() const {
     std::cout << i << "\n";
  }
  C(int i) : i(i) {}
  C& operator=( const C& );
};

C& C::operator=( const C& other) {
  if ( this != &other ) {
    this->~C();                 // lifetime of *this ends
    new (this) C(other);        // new object of type C created
    f();                        // well-defined
  }
  return *this;
}

int main(){
    C c1(1);
    C c2(2);
    c1 = c2;                        // well-defined
    c1.f();
}

In fact my observation is that it works with all major compilers but that makes it not legal...

Bernd
  • 2,113
  • 8
  • 22
  • 2
    your quotes make no sense out of context. You should either quote or summarize basic.life.8 as your quote defines when that happens. – bolov Aug 19 '20 at 20:41
  • I added a reference to a similar but old question here on SO... If you like you can change or extend the quotes – Bernd Aug 19 '20 at 20:48
  • 1
    According to the current wording, you have UB if C happens to be an element of an array or a member of a class. This doesn't make any sense to me. – n. m. could be an AI Aug 19 '20 at 20:58
  • Which wording do you mean? – Bernd Aug 19 '20 at 21:02
  • @Bernd: "*is now replaced with:*" No, it's not. The entire statement has changed. Or at least, the business end of the statement has changed, as it now discusses the relationship between two objects. – Nicol Bolas Aug 19 '20 at 21:02
  • The end is changed right - but it introduces only a new concept called "transparently replaceable" to do the same thing. – Bernd Aug 19 '20 at 21:06
  • 1
    Before you use this in the real world, think about what that assignment operator does if you derive from this thing. – Pete Becker Aug 19 '20 at 22:28
  • Yes - it should be used only for "final" classes more or less - otherwise the rules are violated... – Bernd Aug 20 '20 at 06:37
  • 1
    I've been playing with this for creating compile time matrixes. Since placement new can't be used in compile time code, there are new functions for construction/deletion in c++20. `std::destroy_at` and `std::construct_at` that are explicitly constexpr. These can be used to check for UB by composing/executing a constexpr function. – doug Apr 09 '22 at 18:32

0 Answers0