【问题标题】:Is it acceptable to cast away constness in a move constructor?在移动构造函数中抛弃常量是否可以接受?
【发布时间】:2014-10-24 09:27:05
【问题描述】:

假设我有一个类 Foo,它有一个指向 Bar 的私有指针:

class Foo
{
private:
  Bar * bar;

public:
  Foo () : bar (new Bar ())
  {}

  ~Foo ()
  {
    delete bar;
  }
};

如果指针 bar 永远不应重新分配给不同的实例,那么将指针本身设为 const 以阻止我(或维护者)将来这样做是有意义的:

private:
  Bar * const bar;

只要有机会,我就喜欢这样做。

如果我想写一个移动构造函数,它看起来像这样:

Foo (Foo && f) :
   bar (f.bar)
{
  f.bar = NULL;  // uh oh; f.bar is const.
}

我可以通过抛弃f.bar 的常量或不首先使其变为常量来“使错误消失”。这两件事都不是我想做的。我宁愿不完全删除 const ,因为它的存在是有原因的。另一方面,抛弃 constness 为我敲响了警钟,这是我通常不会做的事情。我的问题是:在这样的移动构造函数中抛弃常量是否被认为是可以接受的做法?有没有更好的方法我没有考虑过?

我觉得我的问题和这个问题不一样:Use const_cast to implement the move constructor

【问题讨论】:

  • 如果您需要更改bar,那么很明显它不应该是const。仔细考虑您的设计。
  • 看起来你的班级不应该是可移动的。
  • 在这里使用 const_cast 是未定义的行为。
  • @user657267 我想更改它的唯一时间是在移动构造函数中,并且仅在即将被删除的实例上。这足以阻止我使用 const 似乎很遗憾。

标签: c++ c++11 constants move-semantics


【解决方案1】:

如果您在某些情况下必须更改指针(即使只是一种情况),那么它可能不应该是const

但是,即使抛开这个想法,使用const_cast 从对象中删除常量,然后使用强制转换的结果也会调用未定义的行为。只有 const_cast 一个原本不是 const 的变量才是安全的。

【讨论】:

  • 更准确地说,写入转换结果是未定义的行为。您仍然可以从结果中读取。
  • 我想这一课是我今年学到的关于 const_cast 的正确与未定义行为的使用的一件事:“永远不要修改声明为 const 的变量。”
【解决方案2】:

你基本上是在自相矛盾。
您是在说“我在任何情况下都不想更改它”,而您是在说“我想在移动对象时更改它”。

因此,如果有需要更改的场景,则不是const,您可以放心删除它。

如果您确定想要它const,您可以添加另一个布尔值来确定所有权(如果您需要处理资源生命周期)。因此,只有在调用拥有该对象的析构函数时,才能释放指向的对象。

【讨论】:

  • 我同意我自相矛盾。我不希望它在任何情况下发生变化,唯一的例外是移动构造函数。我想我要说的是很遗憾,只是移动构造函数会阻止我使用 const。
  • 说明你的设计有缺陷。存在可以更改该指针的情况。示例:{ Foo f; Foo f2(std::move(f)); f.somefn(); } 该代码 sn-p 本身没有任何问题,但 somefn() 应该能够依赖 bar 的值保持不变。您已经非常清楚地告诉编译器(以及您的代码的未来读者)一旦 bar 被初始化,它将永远改变。但是由于对象被移出,它确实发生了变化。从而违反了成员的 const-ness。
  • @AndreKostur 这是一个很好的解释,谢谢。它表明“添加可移动性”不仅仅是添加移动构造函数。在所有成员函数中,都需要考虑对象 post move 的行为。
【解决方案3】:

如果可能,请改用unique_ptr

std::unique_ptr<Bar> bar;
Foo(Foo&& f) : bar(std::move(f.bar)){}
// or maybe you won't even have to declare move constructor

这样你不仅会得到更多的安全和舒适,而且你不会不小心用=重写它,你必须打电话给.reset()所以你在做之前会三思而后行(是你的目标,我想)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2010-11-14
    • 2017-03-16
    • 2014-11-08
    相关资源
    最近更新 更多