“重新初始化”/清理类实例的最短和最佳方法

Posted

技术标签:

【中文标题】“重新初始化”/清理类实例的最短和最佳方法【英文标题】:Shortest and best way to "reinitialize"/clean a class instance 【发布时间】:2010-04-18 21:26:39 【问题描述】:

我会保持简短,只是给你看一个代码示例:

class myClass

public:
  myClass();
  int a;
  int b;
  int c;


// In the myClass.cpp or whatever
myClass::myClass( )

 a = 0;
 b = 0;
 c = 0;

好的。如果我知道有一个 myClass 的实例并将一些随机垃圾设置为 a、b 和 c。

在调用类构造函数后将它们全部重置为状态的最佳方法是:0、0 和 0?

我想出了这个方法:

myClass emptyInstance;
myUsedInstance = emptyInstance; // Ewww.. code smell?

或者..

myUsedInstance.a = 0; myUsedInstance.c = 0; myUsedInstance.c = 0; 
我想你知道我想要什么,有没有更好的方法来实现这一点?

【问题讨论】:

【参考方案1】:
myUsedInstance = myClass();

如果使用这种形式,C++11 会非常高效;移动赋值运算符将负责手动清理每个成员。

【讨论】:

现在,如果我想从内部执行此操作怎么办? *this = MyClass()? 不确定,我相信它几乎适用于所有情况。但是我不确定它是否是“未定义的行为” @sameerchaudhari 它可以编译并且可以工作,但我不确定这是否由论文明确定义,或者编译器只是碰巧理解它【参考方案2】:

您可以将clear 实现为任何可交换类型的通用函数。 (可交换的类型很常见,并且在 C++0x 中使用移动构造函数隐式完成。如果您有一个行为适当的复制构造函数和赋值运算符,那么您的类型在当前 C++ 中自动可交换。您可以 customize swapping 为您的也很容易打字。)

template<class C>
C& clear(C& container) 
  C empty;
  using std::swap;
  swap(empty, container);
  return container;

这需要您做的工作最少,尽管它可能看起来稍微复杂一些,因为它只需要完成一次,然后几乎可以在任何地方工作。它使用 empty-swap 习惯用法来说明在分配时不会清除所有内容的类(例如 std::vector)。


如果您发现交换是性能瓶颈(这种情况很少见),请将其专门化(无需更改任何使用 clear)在 myClass 的标题:

template<>
myClass& clear<myClass>(myClass& container) 
  container = myClass();
  return container;

如果 myClass 是一个模板,你不能部分特化 clear,但你可以重载它(再次在类头中):

template<class T>
myClass<T>& clear(myClass<T>& container) 
  container = myClass<T>();
  return container;

myClass 的标头中定义这种特殊化或重载的原因是通过将它们放在一个地方而不是另一个地方来避免违反 ODR。 (即,如果 myClass 可用,它们始终可用。)

【讨论】:

您可能想强调为什么建议这样做,而不是像其他人建议的那样仅仅依赖默认构造函数。 写得很好。我主要指的是这一行:“它使用空交换习语来解释不能清除分配中所有内容的类(例如 std::vector)。”如果没有这些特殊情况,整个设置不会有太大的好处。【参考方案3】:

只需分配给一个默认构造的类,就像你一样。不过,只需使用一个临时的:

struct foo

    int a, b, c;

    foo() :
    a(), b(), c()
     // use initializer lists
;

foo f;
f.a = f.b =f.c = 1;

f = foo(); // reset

【讨论】:

@Oper 这是标准的 C++ 方式来满足您的要求 - 任何经验丰富的 C++ 程序员都会认出这个梗。【参考方案4】:

您可能需要考虑使用新展示位置。这将允许您使用相同的内存但再次调用构造函数。

不过,不要忘记在使用placement new 之前调用析构函数。

【讨论】:

换句话说,你可能不想考虑这个。我只会在非常特殊的情况下这样做,即便如此,也要三思而后行 - a = A() 几乎总是最好的选择。 谢谢——所有其他解决方案都假设您有一个复制构造函数。【参考方案5】:

嗯,有一个更优雅的方式: 使用单个元素创建类的向量并更新该元素调用 构造函数:

std::vector<your_class> YourClasses;
YourClasses.resize(1);
YourClasses[0] = YourClass(...);

YourClass &y_c = *(&YourClasses[0]);
// do whatever you do with y_c
// and then if you want to re-initialize, do this
YourClasses[0] = YourClass(...);
// and voilla, continue working with resetted y_c

【讨论】:

以上是关于“重新初始化”/清理类实例的最短和最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

在单击按钮时重置/重新初始化/重新启动 UIViewController 视图的最简单(正确)方法是啥?

A 和 B 的计数差异最大的最短子串

最短和最长的城市名称

选择最短和最长的字符串

在java中初始化字符串列表的最短方法是啥?

1195.最长&最短文本