其他分享
首页 > 其他分享> > c-可以使用位置“ new”来更改“ const”数据吗?

c-可以使用位置“ new”来更改“ const”数据吗?

作者:互联网

[这是can memcpy() be used to change “const” member data?的后续措施.Idiomatic Way to declare C++ Immutable Classes确实引起了问题,尤其是this回答“在围绕不可变数据设计的语言中,它知道(尽管)(逻辑)不可变也可以“移动”数据”. ]

给定具有const成员的结构

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

持有指向point2d的指针的类可以指向具有不同值的新point2d实例.

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 });
    }
};

酒吧的客户看到:

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

point2d和Bar都完全按照要求工作.是的,point2d是完全不变的.

但是,我真的很喜欢Bar的另一种实现,该实现将point2d实例存储为成员数据.有什么办法可以做到这一点?使用新的放置可能会导致undefined behavior(请参阅注释).

#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 };
    }
};

不能直接使用point2d作为成员数据来解决(潜在的?)未定义行为吗?

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 };
    }
};

哪个是对的?只是布拉夫?还是巴兹还行吗?还是都不是,唯一的解决方案是Bar?

解决方法:

您可以在对象的生命周期结束后重新使用存储.生存期以析构函数调用结束.在技​​术上没有任何问题.

在对象的生命周期结束后使用该对象,就像在我编写此答案时所提供的示例代码所做的那样

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

是未定义的行为.

如果您坚持将点类与const字段一起使用,则可以这样解决:

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

这可能感觉像是不必要的复杂性和可能的​​微观效率低下,但是,不必要的复杂性就是要点类.

标签:placement-new,c,const,immutability
来源: https://codeday.me/bug/20191009/1878367.html