can placement “new” be used to alter “const” data?

橙三吉。 提交于 2019-12-01 07:47:09

问题


[ This is a follow-up to can memcpy() be used to change “const” member data?. And Idiomatic Way to declare C++ Immutable Classes really gets at the issue, especially this answer "In a language designed around immutable data, it would know it can "move" your data despite its (logical) immutability." ]


Given a struct with const members

struct point2d { const int x; const int y; }; // can't change to remove "const"

A class which holds a pointer to point2d can point to a new point2d instance with different values.

struct Bar
{
    std::unique_ptr<point2d> pPt_{ new point2d{ 0, 0 } };
    const point2d& pt() const {
        return *pPt_;
    }

    void move_x(int value) {
        pPt_.reset(new point2d{ pt().x + value, pt().y });
    }
};

Clients of Bar see:

   Bar bar; // (0, 0)
   bar.move_x(3141); // (3141, 0)

Both point2d and Bar are working exactly as desired; yes, point2d is completely immutable.

However, I'd really like a different implementation of Bar that stores the point2d instance as member data. Is there any way to achieve this? Using placement new supposedly results in undefined behavior (see comment).

#include <new>
struct Baz
{
    point2d pt{ 0, 0 };

    void move_x(int value) {
        // ** is this undefined behavior ? **
        new (&pt) point2d { pt.x + value, pt.y };
    }
};

Does not using point2d directly as member data work-around the (potential?) undefined behavior?

struct Blarf
{
    unsigned char pt_[sizeof(point2d)];
    const point2d& pt() const {
        return *reinterpret_cast<const point2d*>(pt_);
    }

    Blarf() {
        new (&pt_) point2d{ 0, 0 };
    }

    void move_x(int value) {
        new (&pt_) point2d{ pt().x + value, pt().y };
    }
};

Which is correct? Just Blarf? Or is Baz also OK? Or neither, and the only solution is Bar?


回答1:


You can reuse the storage after the lifetime of the object has ended. The lifetime ends with the destructor call. There's nothing technically problematic in that.

Using the object after its lifetime has ended, as the presented example code did at the time I wrote this answer in

pt.~point2d();
new (&pt) point2d { pt.x + value, pt.y };

is Undefined Behavior.

If you insist on using the point class with const fields, you can work around that like this:

void move_x( int const value )
{
     auto const old_pt = pt;
     pt.~point2d();
     ::new (&pt) point2d { old_pt.x + value, old_pt.y };
}

That may feel like unnecessary complication and possible micro-inefficiency, but rather, the unnecessary complication is the point class.



来源:https://stackoverflow.com/questions/38270827/can-placement-new-be-used-to-alter-const-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!