清空一个C++;对象 我经常在C++对象中添加空< /代码>方法,用类似于下面的代码清除内部状态。 class Foo { private: int n_; std::string str_; public: Foo() : n_(1234), str_("Hello, world!") { } void Empty() { *this = Foo(); } };
这似乎比在构造函数中复制代码要好,但我想知道当想要清除对象时,This=Foo()是否是一种常见的方法?等着从背后咬我有什么问题吗?还有其他更好的方法来实现这类功能吗?我想让构造函数调用我的函数:清空一个C++;对象 我经常在C++对象中添加空< /代码>方法,用类似于下面的代码清除内部状态。 class Foo { private: int n_; std::string str_; public: Foo() : n_(1234), str_("Hello, world!") { } void Empty() { *this = Foo(); } };,c++,construction,C++,Construction,这似乎比在构造函数中复制代码要好,但我想知道当想要清除对象时,This=Foo()是否是一种常见的方法?等着从背后咬我有什么问题吗?还有其他更好的方法来实现这类功能吗?我想让构造函数调用我的函数: class Foo { private: int n_; std::string str_; public: Foo() { Reset(); } void Reset() { n_ = 1234;
class Foo
{
private:
int n_;
std::string str_;
public:
Foo()
{
Reset();
}
void Reset()
{
n_ = 1234;
str_ = "Hello, world!";
}
};
是的,您不必要先将字符串初始化为空字符串,然后执行赋值,但这更清楚。
< P>也可以考虑使对象不可变,即,当构造时,它们不能被更改。在很多情况下,这可以避免意外的副作用。考虑使用placementnew
:
void Empty() {
this->~Foo();
new (this) Foo();
}
您的代码调用operator=
,这可能会导致各种副作用
根据评论编辑。-该代码定义明确,标准明确允许它。如果我有时间的话,我稍后会把这一段发出去。关于
删除
——当然。我的意思是~Foo()
,这是一个疏忽。是的,罗布也是对的;在这里,调用字符串的析构函数实际上需要销毁对象。是的,这在性能方面是没有效率的(创建另一个foo对象而不是原地工作),如果在构造函数中分配内存时内存严重泄漏,它会咬你一口
调用this->delete和this=new foo()可以使内存更安全,但速度会很慢
如果您想成为超级快速,请创建一个静态空对象字段,并在重置中memcpy它
如果你想快速地分配一个接一个的属性
如果您想保持合理的样式而不重复,请按照Ates Goral的建议从Ctor调用Reset,但您将失去使用默认参数的更快构造。潜在问题?你怎么知道这真的是一个Foo呢?有比你建议的更常见的东西。使用交换 基本上你可以这样做:
T().swap(*this);
由于许多标准容器(所有STL容器?)都有一个固定时间交换方法,因此这是一种清除容器并确保其存储被释放的好方法
类似地,这也是一种“收缩以适应”容器的好方法,但使用复制构造函数而不是默认构造函数。使用此空方法所做的基本上与手动将新构造的对象分配给变量(空函数所做的事情)相同 就我个人而言,我会删除空方法,并用以下内容替换该方法的所有用途:
// 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();
我真的看不出使用这种空方法有什么好处。它隐藏了它所调用的对象的真实情况,名称也不是最佳选择
如果调用者真的想要一个干净的对象,那么他自己构造对象就没有问题了
这似乎比在构造函数中复制代码要好,但我想知道当想要清除对象时,*This=Foo()是否是一种常见的方法
清除对象并不是一件常见的事情:更常见的情况是,对象(甚至可能是不可变对象)被实例化并包含真实数据,或者它没有被实例化
重置的最常见类型是容器。。。但是,您现在不会编写自己的容器类了,是吗
等着从背后咬我有什么问题吗
是的:
- 如果这不是一个真正的
,而是一个Foo
DerivedFoo
- 如果
的赋值运算符不存在,或者它有缺陷(例如,如果它没有定义并且默认运算符不好,例如,因为数据成员是裸指针)Foo
模板空洞重构(T*p)
{
p->~T();
新(p)T();
}
如果构造函数中有动态分配的内存,则这可能是内存泄漏的潜在来源。以下是我的做法:
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);
}
将swap函数放入与Foo类相同的命名空间中。当用户调用swap来交换两个Foo时,依赖于参数的查找会找到它。您也可以使用swap函数实现
操作符=
。哦,天哪。这看起来真是个坏主意。您刚刚删除了this指针(即,您刚刚将该内存返回内存管理器)。如果你幸运的话,你会很快崩溃的。如果没有,您只需将损坏状态提供给谁知道您的程序的哪一部分。不要那样做。你的意思是“this->~Foo()”而不是“删除这个”。即使不删除“this”,它仍然是错误的。您正在对已初始化的内存调用构造函数。对象的std::string字段将被新字段覆盖;它的析构函数不会首先被调用。谢谢你的评论。代码被弄糟了,我现在已经改正了。在我的辩护中,我最初理解错了这个问题,然后重新阅读并编辑了我的帖子。在最初编辑之前,代码实际上是正确的(和现在一样!),我的编辑改进了它。herb sutter不建议这样做:。也就是说,是的,它定义得很好,但一旦你从Foo派生,它就会很难失败。赫伯比我更了解这些东西,还收集了其他问题。Memcpy导致了非POD类型的未定义行为。分配一个新对象并将结果分配给“this”肯定不会达到您的目的。这正是我的想法。这种“对象回收”不会有任何帮助,可能会使维护和调试更加困难。也许“Clear”会是一个更好的名称-许多STL类型都有一个“c”
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);
}