Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ “可以安置吗?”;新";用于更改;常数;数据_C++_Constants_Immutability_Placement New - Fatal编程技术网

C++ “可以安置吗?”;新";用于更改;常数;数据

C++ “可以安置吗?”;新";用于更改;常数;数据,c++,constants,immutability,placement-new,C++,Constants,Immutability,Placement New,[这是对.的后续行动,并且真正解决了这个问题,特别是回答“使用围绕不可变数据设计的语言,它将知道它可以“移动”您的数据,尽管它(逻辑)不可变。”] 给定具有const成员的struct struct point2d { const int x; const int y; }; // can't change to remove "const" 持有指向point2d的指针的类可以指向具有不同值的新point2d实例 struct Bar { std::unique_ptr<po

[这是对.的后续行动,并且真正解决了这个问题,特别是回答“使用围绕不可变数据设计的语言,它将知道它可以“移动”您的数据,尽管它(逻辑)不可变。”]


给定具有
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 });
    }
};
point2d
Bar
都能正常工作;是的,
point2d
是完全不可变的

但是,我确实希望使用另一种
Bar
实现,它将
point2d
实例存储为成员数据。有没有办法做到这一点?使用placement
new
可能会导致(参见注释)


哪个是正确的?只是
Blarf
?或者
Baz
也可以吗?或者两者都没有,唯一的解决方案是
Bar

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

在对象生命周期结束后使用该对象,正如我在

pt.~point2d();
new (&pt) point2d { pt.x + value, pt.y };
是未定义的行为

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

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

这可能会让人觉得不必要的复杂性和可能的微观效率低下,但是,不必要的复杂性是分数等级。

当您链接到的“证据”与新的位置无关时,为什么说新的位置会导致UB?我遗漏了什么?@Lightness链接答案中的一条评论说,位置
new
memcpy()相同。
Oh comments,诸如此类。但我不确定我是否同意萨姆的观点。Placement new就好像破坏了原始文件一样(如果原始文件是可破坏的,则定义良好,如
int
),并用新的内容替换它。请注意,“对象”是内存中的一个区域。但它也有一种类型。这两人在新职位上意见相左。我认为这是否是一个非常有趣的问题。我会先问这个问题。@Dan:我不知道,只要你想解决该数组的潜在对齐问题,我想不出它有什么问题。更让人困惑的是,如果你显式调用对象的析构函数,然后用placement new重新构建它,如:
pt.~point2d();新的(&pt)点2d{x,y}?这似乎实际上是一致的,因为原始对象的生命周期已显式结束,并在其位置重建了一个新对象…@Dan:我猜您的编译器将完全优化掉它。这一切都是关于形式的,它告诉编译器,它不能根据仅因为形式的假设而成立的假设来做太聪明的事情。@Dan,虽然这在技术上是对您特定问题的正确答案,但请注意回答的最后一行“这可能让人觉得不必要的复杂化和可能的微观效率低下,但是,不必要的复杂化是point类。”还有其他更好的处理方法“像这样的把戏通常会导致多年后的嘲笑,人们会诅咒你和你的亲人。我猜这
move\u x
实现大概就是容器上的“替换安放”操作所能做的。如果有一个硬要求,你不能修改point2d类定义,然后编写自己的point2d类。尽可能使用该类,并在最后一次可能的机会转换为垃圾point2d类。看起来它应该被当作“视图”使用。@Andrew有一个很好的解释。
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 };
    }
};
pt.~point2d();
new (&pt) point2d { pt.x + value, pt.y };
void move_x( int const value )
{
     auto const old_pt = pt;
     pt.~point2d();
     ::new (&pt) point2d { old_pt.x + value, old_pt.y };
}