【问题标题】:move-construct object with placement new移动构造对象,放置新
【发布时间】:2016-11-05 10:23:44
【问题描述】:

通过placement new来移动构造对象不是UB吗?

假设我有这个代码:

class Foo {
public:
    Foo() { foo_ = new int; }
    ~Foo() { delete foo_; }
    Foo(Foo &&f) {
        foo_ = std::swap(f.foo_, foo_);
    }
private:
    int* foo_;
}

void bar() {
    void* pMem = malloc(sizeof(Foo));
    Foo f1;
    // move-construct with placement new:
    new((Foo*)pMem) Foo(std::move(f1)); // f2 in *pMem

    // now f1 will contain a pointer foo_ of undefined value
    // when exiting scope f1.~Foo(){} will exhibit UB trying to delete it
}

如果不是很明显,f1 的成员 foo_ 在通过放置 new 和 move 构造构造第二个 foo 后将有一个未定义的值(这个未定义的值来自未初始化的 Foo f2 的 foo_ 在其移动构造函数中,因为这些值是 交换了

因此,当退出 bar() 的作用域时,f1 的析构函数会尝试删除一个无效(未初始化)的指针。

【问题讨论】:

  • 放置或其他new获取内存。构造函数将内存转换为对象。 new 不在乎你对内存做了什么。构造函数并不关心你如何获得内存。是的,这种行为是未定义的,但它与您分配有问题的对象的方式无关。可以是自动的或任何其他类型的。

标签: c++ c++11 placement-new move-constructor


【解决方案1】:

这与安置新无关。这段代码会有完全相同的问题:

void bar() {
    Foo f1;
    Foo f2(std::move(f1));
}

每个构造的对象最终都会被破坏,所以不管你是否使用placement-new,你的move-constructor都会因为让moved-from对象处于无效状态而搞砸.从一个对象移动并不意味着它不会被破坏。它会。当你离开它时,你必须让一个有效的物体在后面。

Foo(Foo &&f) : foo_(nullptr) {
    std::swap(f.foo_, foo_);
}

将修复错误。

【讨论】:

  • 有趣,我不知道您可以使用带有移动构造函数的初始化列表。这确实可以修复错误。
  • @BogdanIonitza:它们可以是 any 构造函数的一部分。移动构造函数在这方面并不特殊。
  • @NicolBolas 现在我想起来了。不过我之前从来没想过
猜你喜欢
  • 1970-01-01
  • 2022-01-13
  • 2019-10-08
  • 2018-01-11
  • 1970-01-01
  • 2023-04-08
  • 2021-09-15
  • 2011-10-07
相关资源
最近更新 更多