c++ - 可以使用放置 "new"来更改 "const"数据吗?

标签 c++ constants immutability placement-new

[这是 can memcpy() be used to change “const” member data? 的后续内容。和Idiomatic Way to declare C++ Immutable Classes真正解决了这个问题,尤其是 this回答“在围绕不可变数据设计的语言中,它知道它可以“移动”您的数据,尽管它具有(逻辑)不变性。” ]


给定一个带有 const 成员的 struct

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 bar; // (0, 0)
   bar.move_x(3141); // (3141, 0)

point2dBar 都完全按照预期工作;是的,point2d 是完全不可变的。

但是,我真的很喜欢 Bar 的不同实现,它将 point2d 实例存储为成员数据。有什么办法可以实现这一点吗?使用放置 new 可能会导致 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 };
    }
};

哪个是正确的?只是布拉夫?或者Baz也可以吗?或者两者都不是,唯一的解决方案是 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 };
}

这可能感觉像是不必要的复杂化和可能的微观低效率,但更确切地说,不必要的复杂化是点类。

关于c++ - 可以使用放置 "new"来更改 "const"数据吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38270827/

相关文章:

c++ - 迭代 vector 并将迭代器实际指向的对象添加为 map 中的键

java - 如何使包含一系列可变类的类不可变?

C++ STL 问题 : allocators

c++ - 如何获取md5sum命令并获取代码中的字符串输出

c++ - 有没有更快的方法可以在std::vector中插入元素

python - 非变异 'add' 到集合的命名约定

java - 在java中获取一个字符串作为引用

c++ - 断点未命中

c# - 如何在 C# 中声明编译时常量函数

c++ - const_cast 的合法用途是什么