2

Is it a viable solution to use placement new to circumvent copy assignment?

I have a member object that contains const members. The object itself is meant to be created at runtime, but it's members are meant to be const.

I was wondering whether I could use placement new to circumvent the copy assignment at runtime?

#include <new>
#include <iostream>
struct A {
    const int a;
    A() : a(0) {};
    A(int a) : a(a){}
};

struct B {
    A a;
    void createA() {
        new(&a) A(69);
    }

    void useA() {
        std::cout << a.a << std::endl;
    }

};

int main(void) {

    B b;
    b.createA();
    b.useA();
    return 0;
}

It compiles and runs but does it invoke UB?

David G
  • 94,763
  • 41
  • 167
  • 253
Raildex
  • 3,406
  • 1
  • 18
  • 42
  • 1
    Yes, it does invoke UB. – Sam Varshavchik Apr 25 '21 at 19:53
  • You should not works around code by doing hacks. It make the code hard to understand and make it subject to undefined behavior. Also, if a member was made constant in a class, then the class was designed assuming that the value will not change. Compiler could also assume that in some context. If you cannot modify the code, then simply use another distinct `B` object when you need a new `A` sub-object. – Phil1970 Apr 25 '21 at 21:13
  • @SamVarshavchik Can you tell me the passage of the standard that says it's UB? I can't seem to find it. – Raildex Apr 28 '21 at 05:35
  • 1
    In C++ every object is constructed, and then destroyed when its scope ends. The shown code constructs another object in the same memory as another object that was constructed, without destroying the first object. This is undefined behavior. – Sam Varshavchik Apr 28 '21 at 11:03

1 Answers1

1

You should not do this, though it will technically work in this case.

By circumventing the copy assignment you are not giving the object a chance to perform any required cleanup on the old data (e.g. freeing memory resources). In this example, you are calling the new placement operator before the lifetime of a ends.

The following will work as it does not violate a's lifetime:

a.~A(); // manually destruct a, end it's lifetime
new(&a) A(69); // construct a new instance and start a new lifetime
qz-
  • 674
  • 1
  • 4
  • 14
  • @Phil1970 I'm not sure I see your point. There's no reason A's destructor should have any problems on the second destruction. The destructor is only called once for each instance. – qz- Apr 25 '21 at 21:52
  • What if I know that the object i want to replace does not have any resources to clean? I'd like to be const-correct but since I need to initialize other objects (which I can't construct via list init because its third party API) to construct `A` I don't see a different solution than placement new. – Raildex Apr 26 '21 at 05:31