清空C ++对象

时间:2009-01-12 17:38:20

标签: c++ construction

通常我会在我的C ++对象中添加Empty方法,以使用类似于以下内容的代码清除内部状态。

class Foo
{
private:
    int n_;
    std::string str_;
public:
    Foo() : n_(1234), str_("Hello, world!")
    {
    }

    void Empty()
    {
        *this = Foo();
    }
};

这似乎比在构造函数中复制代码更好,但我想知道*this = Foo()是否是想要清除对象时的常用方法?这有什么问题等着咬我的背面?有没有其他更好的方法来实现这类事情?

10 个答案:

答案 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建议,但你将失去使用默认参数的更快的构造。