可以放置“新"用于改变"const"标记.数据? [英] can placement "new" be used to alter "const" data?

查看:98
本文介绍了可以放置“新"用于改变"const"标记.数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[这是对 can memcpy( )用于更改"const"成员数据?.而宣告C ++不可变类的惯用方式确实引起了问题,尤其是回答在围绕不可变数据设计的语言中,尽管它具有(逻辑上)的不变性." ]

[ 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." ]

structconst个成员

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

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

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

Bar的客户请参阅:

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

point2dBar均按要求工作.是的,point2d是完全不变的.

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

但是,我真的很希望Bar的另一种实现将point2d实例存储为成员数据.有什么办法可以做到这一点?使用放置new可能会导致未定义的行为(请参见注释).

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

不是直接使用point2d作为成员数据是否可以解决(潜在的?)未定义行为?

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

哪个是正确的?只是Blarf?还是Baz还可以吗?还是都不是,唯一的解决方案是Bar?

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

推荐答案

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

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

是未定义的行为.

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

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.

这篇关于可以放置“新"用于改变"const"标记.数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆