【问题标题】:Destructor of struct called before assignment operator在赋值运算符之前调用的结构的析构函数
【发布时间】:2014-11-27 04:57:57
【问题描述】:

我有一个结构体 Foo,其指针数组为 Bar。

struct Foo
{
    Bar* _BarList;

    Foo()
    {
        _BarList = new Bar[1];
        _BarList[0] = Bar(10, 20);
    }

    Foo& operator=(const Foo& foo)
    {
        Bar* tmpBarList = new Bar[1];

        tmpBarList[0] = foo._BarList[0];

        delete[] _BarList;

        _BarList = tmpBarList;

        return *this;
    }

    ~Foo()
    {
        delete[] _BarList;
    }
};

我这样称呼它

Foo baz = fooFunc();

(似乎)如果我在函数 (fooFunc) 中创建 Foo (f) 的实例并返回它,则在返回值之前调用析构函数,因为我丢失了 _BarList 的内容。

这是有道理的,因为它是在函数中创建的。这是一个例子。

Foo fooFunc()
{
    Foo f = Foo();
    return f;
}

如果我在返回时直接返回 Foo 的一个实例,则在调用 equals 运算符(通过调用行上的 equals 语句)之前,不会调用该项目的析构函数。

Foo fooFunc()
{
    return Foo();
}

我认为这是有道理的,因为我在对象内部创建 Foo,并且在返回对象之前清除了所有内容。

我想我可以通过这样的返回来解决这个问题(在编写一个新的构造函数来获取 Foo 之后):

Foo fooFunc()
{
    Foo f = Foo();
    return Foo(f);
}

1) 我的假设是否正确?

2) 是否有另一种不需要调用这么多重复赋值运算符的方法?

编辑:请考虑这个函数通常会做的不仅仅是返回 Foo()!

【问题讨论】:

标签: c++ operator-overloading assignment-operator


【解决方案1】:

你的班级违反了Rule of three。您有一个析构函数和一个复制赋值运算符,但没有复制构造函数。而默认的绝对做你需要的。

并注意所有这些行:

Foo f = Foo();
return Foo(f);
Foo baz = fooFunc();

使用复制构造函数,而不是赋值运算符。赋值运算符仅用于分配给 现有 对象,从不用于创建/初始化新对象。

【讨论】:

  • 我不确定Foo f = Foo(); 使用复制构造函数,它使用赋值运算符,编译器的作用与编写Foo f 相同。没有?
  • @jpo38 Foo f = Foo() 使用复制构造函数从临时的Foo() 复制。初始化总是使用一个ctor,从不一个赋值操作
  • 我的错误,我的意思是问“你确定Foo f = Foo() 使用复制构造函数”。答案是肯定的,如下所示:stackoverflow.com/questions/1051379/…
【解决方案2】:

我认为您遇到的不同行为是由于编译器优化造成的。

无论如何,

Foo baz = fooFunc();

需要一个复制构造函数才能工作,因为它将从 fooFunc 返回的对象构造一个新对象。

例如

Foo(const Foo& foo) : _BarList( NULL )
{
    ::operator=( foo );
}

这将保证 fooFunc() 返回对象被复制到本地声明的 Foo baz 对象。

注意:实际上,从复制构造函数调用operator= 是一种不好的做法(但我在这里提到它是为了给你一个快速的答案,它适用于你的情况)。查看此帖子:Copy constructor and = operator overload in C++: is a common function possible?

【讨论】:

  • 甜蜜。说得通。为什么是 _BarList 位?
  • 你需要将_BarList设置为NULL,否则delete[] _BarList;时::operator=会崩溃。
  • 所以,如果我在 _BarList 中没有项目(即,我没有在其上调用 new[]),将其设置为 NULL(在我的情况下为 0)不会导致它在然后我调用 delete[] 就可以了?
  • 是的,在0 上调用delete 是安全的
  • 您的operator= 将首先删除this->_BarList,然后将foo 的_BarList 内容复制到this->_BarList。但是如果_BarList 没有被初始化,delete [] _BarList 将会崩溃。 delete [] NULL 不会崩溃。
猜你喜欢
  • 2012-04-01
  • 2017-06-12
  • 2017-10-06
  • 2014-04-18
  • 1970-01-01
  • 1970-01-01
  • 2018-03-22
  • 2013-03-26
  • 2011-02-08
相关资源
最近更新 更多