首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >拥有指针成员的C++移动构造函数

拥有指针成员的C++移动构造函数
EN

Stack Overflow用户
提问于 2017-05-09 18:38:07
回答 4查看 2.2K关注 0票数 2

我在问一些看起来很琐碎但我有问题的事情。为了解释一下,让我们假设一个像这样的结构:

代码语言:javascript
复制
class MyClass{
    int* m_Number;
public:
    int value() const {return *m_Number;}
    void setValue(int val){*m_Number=val;}
    MyClass() : m_Number(new int(3)){}
    ~MyClass() {if(m_Number) delete m_Number;}
    MyClass(const MyClass& other):m_Number(new int(*other.m_Number)){}
    MyClass& operator=(const MyClass& other){if(m_Number) *m_Number=*other.m_Number; else m_Number=new int(*other.m_Number); return *this;}
    MyClass& operator=(MyClass&& other){std::swap(m_Number,other.m_Number); return *this;}
    MyClass(MyClass&& other){
            //????
    }
}

我应该放什么进去?我的选择是:

1)

代码语言:javascript
复制
    MyClass(MyClass&& other)
            :m_Number(other.m_Number)
    {
            other.m_Number=nullptr;
    }

但是,移出对象不处于有效状态。调用value()应该返回一些有效但未定的内容,而这里我只是分段错误。我可以检查m_Number的值()和setValue(),但您意识到这在实际代码中是一个很大的阻力。

2)

代码语言:javascript
复制
    MyClass(MyClass&& other)
            :m_Number(other.m_Number)
    {
            other.m_Number= new int(3);
    }

但是,可以抛出的move构造函数是no go (或者至少据我理解),它也是性能增强的阻力,实际上,这段代码与复制构造函数相同或更糟。

你认为如何?

我错过了什么吗?

有更好的方法吗?

提前感谢

编辑:这个问题得到了性病委员会召集人的答复,从根本上说它与这个帖子的答案不一致。您可以在本文https://herbsutter.com/2020/02/17/move-simply/中找到它。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-05-09 18:47:42

首先,这里没有理由使用newdelete,您应该使用make_unique<int>来创建对象,使用unique_ptr<int>来自动管理对象。但这并不能解决您的问题,移动构造器可以做什么。除了您建议的两个选项之外,还有其他一些选择:

3)不要给它移动构造函数,只需将其作为可复制的

4)文档说明不允许对移动对象调用valuesetValue,并将移动对象保留为空指针。根据您的程序中发生的移动位置,这可能会很好。如果移动-从对象从来没有访问,一切只是工作。

( 4a)如上文所述,但如果发生这种情况,则应加上健全检查:

代码语言:javascript
复制
int value() const {
  assert(m_Number != nullptr);
  return *m_Number;
}

或者:

代码语言:javascript
复制
int value() const {
  if (m_Number == nullptr)
    throw std::logic_error("accessed a moved-from object");
  return *m_Number;
}

5)向setValue添加检查,以便在当前为空的情况下用新的int重新初始化对象,并使value返回一些默认值:

代码语言:javascript
复制
int value() const { return m_Number ? *m_Number : 0; }

void setValue(int val) {
  if (!m_Number)
    m_Number = new int(val);
  else
    *m_Number = val;
}
票数 3
EN

Stack Overflow用户

发布于 2017-05-09 18:51:38

.value()调用中取消引用指针。在m_Number无效的情况下,您将始终分割错误。

移动构造函数的第一个解决方案是正确的,您应该将“other”对象设置为默认状态。要解决这个问题,您可以抛出.value()方法,或者在不存在资源的情况下返回默认值。

您的析构函数已经说明了null大小写,所以请确保其馀部分也说明了这一点。

票数 1
EN

Stack Overflow用户

发布于 2017-05-09 19:02:31

  1. 如果修改MyClass使m_Number = nullptr是一个有效的状态是合理的(如果它也是默认状态的话),那么第一种方法可能是最好的方法。如果没有与MyClass关联的堆内存不是一个有效的状态,那么您应该在std::unique_ptr中分配它,并传递一个指向它的原始指针,而不是实现一个移动构造函数。
  2. 如果1.不是一个选项,这是一个合理的方法。虽然分配不需要的内存的性能肯定会受到影响,但这很小,特别是考虑到您正在构建一个类作为此操作的一部分(它本身需要内存)。如果像您的例子一样需要一小块内存,内存分配器可能会从自己的池中提取它,而不需要系统调用。如果它是一大块内存(正如我所期望的,因为您正在实现移动语义),那么在大多数现代操作系统上,它将是一个延迟分配(因此它仍然比复制构造函数更好)。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43877502

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档