通常我会在我的C ++对象中添加Empty
方法,以使用类似于以下内容的代码清除内部状态。
class Foo
{
private:
int n_;
std::string str_;
public:
Foo() : n_(1234), str_("Hello, world!")
{
}
void Empty()
{
*this = Foo();
}
};
这似乎比在构造函数中复制代码更好,但我想知道*this = Foo()
是否是想要清除对象时的常用方法?这有什么问题等着咬我的背面?有没有其他更好的方法来实现这类事情?
答案 0 :(得分:11)
我让构造函数调用我的函数:
class Foo
{
private:
int n_;
std::string str_;
public:
Foo()
{
Reset();
}
void Reset()
{
n_ = 1234;
str_ = "Hello, world!";
}
};
是的,您首先将字符串初始化为空字符串,然后进行分配,但这更加清晰。
答案 1 :(得分:9)
潜在问题?你怎么知道*这真的是一个Foo?
答案 2 :(得分:6)
使用此Empty方法执行的操作与将新构造的对象手动分配给变量(Empty函数执行的操作)基本相同。
就个人而言,我将删除Empty方法,并用以下方法替换该方法的所有用法:
// let's say, that you have variables foo and pfoo - they are properly initialized.
Foo foo, *pfoo;
// replace line "foo.Empty()" with:
foo = Foo();
// replace line "pfoo->Empty()" with:
delete pfoo;
pfoo = new Foo();
// or
*pfoo = Foo();
我觉得这个Empty方法没有任何优势。它隐藏了被称为女巫的对象真正发生的事情,这个名字也不是最好的选择。
如果调用者真的想要一个干净的对象 - 他自己构建对象没有问题。
答案 3 :(得分:5)
另外,考虑使对象不可变,即,在构造时,它们不能被更改。在很多场景中,这可以避免意外的副作用。
答案 4 :(得分:4)
有些东西比你建议的更为常见。使用交换。
基本上你做的是这样的事情:
T().swap(*this);
因为许多标准容器(所有STL容器?)都有一个恒定的时间交换方法,这是清除容器并确保它的存储空间释放的一种简单方法。
同样,它也是“缩小以适应”容器的好方法,但是使用复制构造函数而不是默认构造函数。
答案 5 :(得分:2)
考虑使用展示位置new
:
void Empty() {
this->~Foo();
new (this) Foo();
}
您的代码会调用operator =
,这可能会导致各种副作用。
编辑以回应评论。 - 这段代码肯定定义明确,标准明确允许它。如果我找到时间,我将在稍后发布该段落。关于delete
- 当然。我的意思是~Foo()
,这是一种疏忽。是的,Rob也是对的;在这里实际需要破坏对象来调用字符串的析构函数。
答案 6 :(得分:2)
如果构造函数中有动态分配的内存,则可能是内存泄漏的潜在来源。
答案 7 :(得分:2)
我是这样做的:
class Foo {
private:
int n_;
std::string str_;
public:
Foo() : n_(1234), str_("Hello, world!")
{
}
void Empty()
{
Foo f;
swap(f);
}
void swap(Foo & other) {
std::swap(n_, other.n_);
swap(str_, other.str_);
}
};
void swap(Foo & one, Foo & other) {
one.swap(other);
}
将交换函数放入与Foo类相同的命名空间中。当用户执行调用swap以交换两个Foo时,依赖于参数的查找会找到它。您也可以使用交换功能实现operator=
。
答案 8 :(得分:1)
这似乎比在构造函数中复制代码要好,但是我想知道在想要清除对象时,* this = Foo()是否是一种常见方法?
清除一个对象并不常见:更常见的是,一个对象(甚至是一个不可变对象)被实例化并包含真实数据,或者它没有被实例化。
重置的最常见的事情是容器...但是,你现在不会编写自己的容器类,是吗。
这有什么问题等着咬我的背面?
是:
Foo
,而是DerivedFoo
Foo
的赋值运算符不存在,或者它有错误(例如,如果它没有定义且默认运算符不好,例如因为数据成员是一个裸指针)。 / LI>
还有其他更好的方法可以实现这类目标吗?
是的,也许免费功能会更好(避免上述问题):
template<class T> void reconstruct(T* p)
{
p->~T();
new (p) T();
}
答案 9 :(得分:-2)
是的,这在性能方面效率不高(创建另一个foo对象而不是在其中工作),如果你在构造函数中分配了内存泄漏,那么它会咬你。
在内存方面让它更安全,可以调用this-&gt; delete和this = new foo() - 但它会很慢。
如果你想超高速创建一个静态空对象字段并在重置中记忆它。
如果你想快速分配属性一个接一个。
如果你想保持合理的风格而没有重复调用从Ctor重置为Ates Goral建议,但你将失去使用默认参数的更快的构造。