你的类的std :: unique_ptr和reset()或Reset方法?

时间:2015-02-13 19:54:36

标签: c++ c++11 memory-management class-design unique-ptr

使用std::unique_ptr::reset,您可以轻松地将实例恢复到新的状态。

Pre-C ++ 11,为了实现类似的行为,我看到很多类定义了一个Reset()方法,它重置了所有内部成员。但是现在,我认为只需使用构造函数和析构函数并reset unique_ptr到类的新实例即可。对于为什么您仍然偏好Reset()方法,我是否缺少任何好处,或者我们应该始终只使用unique_ptrreset将其用于新实例,只要我们想“重置“我们的班级?

我能想到的唯一好处就是你保存了有时很昂贵的分配/删除。 当然,成本是维护Reset()函数并确保其与其他代码更改保持同步的复杂性。

是吗?这只是一个复杂性和性能问题?

4 个答案:

答案 0 :(得分:4)

这是将类的状态重置为默认构造状态的非常好的通用方法:

// Previously constructed MyClass myvalue = ...
myvalue = MyClass{};

这涉及两个操作:

  1. 默认构造。
  2. 移动作业。
  3. 理想情况下,这些都应该便宜。

答案 1 :(得分:0)

  

我能想到的唯一好处就是你省了一个   分配/删除有时可能很昂贵

不仅可能昂贵的分配,而且可能的内存碎片,糟糕的局部性(感谢@Cris在我脑海中搜索的术语),在频繁重置期间,最终会引入巨大的性能问题。

unique_ptr并不意味着重置您的实例状态。  unique_ptr::reset重置unique_ptr所有权结果调用析构函数" old"实例。

因此,这与您的实例Reset方法完全不同。

如果重置

  • 您没有实例化新内存 - >亲

  • 可能会重复使用相同的内存而不会丢弃它,因此请保持数据的对齐和紧密包装(取决于 你实施Reset方法的方式) - >亲

  • 非安全内存管理,导致内存泄漏 - >缺点

如果是unique_ptr

  • 没有指针别名和内存管理控制 - >亲
  • 每次分配新实例 - >缺点

所有专业缺点自然是有争议的,取决于具体的实施和实际要求。

答案 2 :(得分:0)

分配/删除是一个成本,但是还有通过指针访问对象的额外间接级别的成本。例如,较差的数据位置。

也可以在只有引用或指针的上下文中调用Reset()函数。应该知道对象由unique_ptr管理的唯一对象是所有者。在其他情况下,最好使用引用或指针。

但只要你知道成本并且只有主人想要重置,我就不会发现这样做有什么不妥。

当然,这在C ++ 11中并不新鲜,使用堆分配的对象始终可以做到这一点。这只是unique_ptr如何让生活更轻松的一个例子。

答案 3 :(得分:0)

我认为你在这里搞混合了。

unique_ptr这样的{p> shared_ptr是代表所有权的构造。 除非您自己提供复制构造函数和复制赋值运算符,否则使用unique_ptr意味着您的类既不能复制也不能复制分配。 这可能是额外的工作。

因此,如果您仍想提供重置方法但不想手动重置每个成员变量的代码,您可以执行以下操作:

MyClass::Reset()
{
    this->~MyClass();
    new(this) MyClass();
}

会将您的实例重置为默认创建状态。

这种方法的缺点是

  • 不例外保存,所以如果您的构造函数可以抛出,则会遇到问题。
  • 您的成员在内部使用的动态内存将被丢弃,不会直接重复使用。例如,释放vector成员及其在堆上的相关内存,而不是重用。

实际上你也可以实现Reset之类的

MyClass::Reset()
{
    *this = MyClass();
}

虽然这可能比以前的解决方案慢。