Date: Mon, 29 Apr 2019 11:54:45 +0200
Mohamed Khaled via Std-Discussion wrote:
> Hello All,
>
> ```
> #include <memory>
> #include <iostream>
>
> struct C
> {
> const int x;
> };
>
> void foo1()
> {
> C c{1};
> c.~C();
> new (&c) C{2};
> std::cout << c.x << std::endl;
> }
>
> std::unique_ptr<C> foo2_a()
> {
> std::unique_ptr<C> c(new C{1});
> c->~C();
> new (c.get()) C{2};
> return c;
> }
>
> void foo2_b(std::unique_ptr<C> c)
> {
> std::cout << c->x << std::endl;
> }
>
> int main()
> {
> foo1();
> foo2_b(foo2_a());
> }
> ```
>
> As far as I understand, in foo1() one should invoke std::launder whenever c
> is being accessed after the placement. Should it also be invoked in foo2_b,
> that is when the access to the object whose memory is being reused is in
> some separate function rather than the one where the placement happened.
std::launder is used only when you only have access to the new element through the old object, when for example the class has a const data member. In your case, you are right that in foo1 you should use std::launder. This *also* applies to foo2_b, since the pointer stored in the unique_ptr points to the old object and it can only be used to access the new object with std::launder.
> More generally should the placement new always be coupled with std::launder?
Not necessarely, only when you are using placement new on a variable and/or not reassignable buffer. If you use a pointer for example you can do this:
ptr = new (ptr) C{2};
And there you don't have to use placement new.
> Hello All,
>
> ```
> #include <memory>
> #include <iostream>
>
> struct C
> {
> const int x;
> };
>
> void foo1()
> {
> C c{1};
> c.~C();
> new (&c) C{2};
> std::cout << c.x << std::endl;
> }
>
> std::unique_ptr<C> foo2_a()
> {
> std::unique_ptr<C> c(new C{1});
> c->~C();
> new (c.get()) C{2};
> return c;
> }
>
> void foo2_b(std::unique_ptr<C> c)
> {
> std::cout << c->x << std::endl;
> }
>
> int main()
> {
> foo1();
> foo2_b(foo2_a());
> }
> ```
>
> As far as I understand, in foo1() one should invoke std::launder whenever c
> is being accessed after the placement. Should it also be invoked in foo2_b,
> that is when the access to the object whose memory is being reused is in
> some separate function rather than the one where the placement happened.
std::launder is used only when you only have access to the new element through the old object, when for example the class has a const data member. In your case, you are right that in foo1 you should use std::launder. This *also* applies to foo2_b, since the pointer stored in the unique_ptr points to the old object and it can only be used to access the new object with std::launder.
> More generally should the placement new always be coupled with std::launder?
Not necessarely, only when you are using placement new on a variable and/or not reassignable buffer. If you use a pointer for example you can do this:
ptr = new (ptr) C{2};
And there you don't have to use placement new.
-- - Nicolas
Received on 2019-04-29 04:56:26