【问题标题】:move assignment to object with const value将赋值移动到具有 const 值的对象
【发布时间】:2018-04-16 23:06:01
【问题描述】:

我有一个这样的结构:

struct OBJ {
  int x;
  const int y;
  OBJ& operator=(OBJ &&oth)
  {
    y = oth.y; // this is disallowed
    return *this;
  }
}

还有一个示例代码

void func() {
  static OBJ obj;
  OBJ other; // random values
  if(conditon)
    obj = std::move(other); //move
}

我理解这是因为 objNon const 带有 const 成员 y 的 OBJ。我不能只改变 y 但我应该能够改变整个对象(调用析构函数和构造函数)。这是可能的还是唯一正确的解决方案是在y 之前删除我的const,并记住不要意外更改?

我需要在func 调用之间存储我的static obj,但如果条件为真,我想移动其他对象来代替这个静态对象。

【问题讨论】:

  • [Off Topic] obj = std::move(OBJ()); 不需要。 OBJ() 已经是一个右值,所以 obj = OBJ(); 做同样的事情。
  • 您将需要编写自己的移动赋值运算符(当您使用它时,其他特殊的成员函数)
  • @NathanOliver 这个代码只是真实的例子func这个对象已经存在,我想移动它而不是构造!
  • 也许你也应该read a good beginners book,因为你有一个构造函数,它们不应该返回任何东西。

标签: c++ c++11 move


【解决方案1】:

你做错了构造函数。构造函数应该初始化,而不是赋值:

OBJ(OBJ &&oth) : y(oth.y) {}
//             ^^^^^^^^^^

另外,构造函数不能return *this,因为它们没有返回类型。

类的赋值运算符没有意义,因为该类具有不可赋值的成员(即常量)。 (你当然可以编写一个不修改 const 成员的自定义赋值,但这样你就会有一个非常奇怪的类,它的行为非常令人惊讶。)

【讨论】:

  • 抱歉,我编辑了问题。应该有 operator= 而不是构造函数。很抱歉造成混乱
  • @S.R:也更新了答案。
  • 是的,但这仍然适用于构造函数,而不是赋值。 @kerrek-sb
  • @S.R: 第二段 :-)
  • 好的。所以你说我必须在我的变量y 中删除const。问题是如何更改包含 const 成员 (y) 的整个静态对象。不是第一次如何构建它。
【解决方案2】:

这样写移动赋值运算符怎么样:

OBJ& operator=(OBJ&& other) {
    this->~OBJ();
    new(this) OBJ(other.x, other.y);
    return *this;
}

你还需要一个构造函数:

OBJ(const int x, const int y)
    : x(x), y(y)
{
}

【讨论】:

  • 在具有 const 成员的非动态对象上放置新的不是 UB 吗?!
  • 好吧,这个解决方案在很大程度上受到了这个答案的启发:stackoverflow.com/a/39382728/1003701 这个问题是关于std::launder 的,似乎洗钱是充分利用我的回答中提到的技术而无需进入的方法未定义的行为登陆。另见:en.cppreference.com/w/cpp/utility/launder
  • @MiroslavMares 很好,但是当我的结构中没有微不足道的成员时这是否安全? en.cppreference.com/w/cpp/utility/launder 看起来不错,但它是 c++17 我需要 C++14 / C+11 解决方案。
  • @S.R - 如果“重建”可能因异常而失败,这是非常不安全的。然后你有一个僵尸对象 - 一个活着但死了的对象。
  • 现在我删除了const,但我不喜欢这段代码。这个变量应该是常量。它不是在改变,而是在移动。 (旧的被破坏了,新的只是在内存中改变了位置,所以从逻辑上讲,我认为这应该有效)。我正在等待 std::launder。
【解决方案3】:

我建议转到std::unique_ptr:

void func() {
  static std::unique_ptr<OBJ> obj = std::make_unique<OBJ>();
  std::unique_ptr<OBJ> other = std::make_unique<OBJ>(); // random values
  if(condition)
    obj = std::move(other); //move
}

在许多需要移动无法移动的东西、保存未知的多态类型或任何其他您无法处理实际类型的情况下,这应该是您的选择。

【讨论】:

  • 这适用于 const 值吗?它看起来像它做的工作!很好的解决方案!
  • @S.R 它应该可以工作。好吧,你可以看到它确实如此。我会尽可能客观地建议将其标记为已接受的答案:-)
  • @amir-krish 是的,我会在测试后立即接受它。我还有一个问题我可以告诉编译器只接受我的结构作为 uniq_ptr 吗?所以唯一的方法是生成 uniq 指针。我想知道私有构造函数和 make_obj 函数作为朋友。
  • @S.R 由 RValues 大师本人:stackoverflow.com/a/17135547/2085626 另一个选项可以在这里找到:seanmiddleditch.com/…
猜你喜欢
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
  • 2021-10-26
  • 1970-01-01
相关资源
最近更新 更多