C ++ 11移动分配和复制分配(操作员) - 使用删除

时间:2015-08-27 00:41:00

标签: c++11 memory-leaks move-semantics raw-pointer

我目前的理解是两者 C ++ 11移动和复制分配操作符应该调用delete来防止内存泄漏,但是C ++ 11移动和复制构造器应该

如果我的理解是正确的,那么构造函数不需要调用delete,但我不确定为什么。请考虑以下示例:

class my_class
{
    my_class(int num_data) : my_data{new double[num_data]}, my_data_length{num_data}
    {
    }

    // This class manages a resource
    double *my_data;
    int my_data_length;
}

// Big 4 go here - see wikipedia example below.

my_class a(10);
my_class b(10);
my_class c(10);

a = b; // Need to delete old storage contained in a before reallocating
a(c); // For some reason we don't need to delete the old storage here? I find this puzzling

查看此wikipedia文章中的示例代码,我很清楚:

  • 移动构造函数不会泄漏,因为资源已传输。 类到期时指向的任何已分配数据将转移到过期类,并由过期类的析构函数删除。

    < / LI>
  • 然而,我对复制构造函数是否泄漏感到困惑。

  • 移动分配操作员可能不会泄漏,因为它只是交换指针。

  • 我再次被复制作业操作员搞糊涂了。我不确定为什么需要使用临时对象?我的猜测是tmpother拥有的资源在这个函数结束时超出范围时会被销毁? (除了tmp的资源与this类中的指针交换了吗?)

为方便起见,下面提供了以下代码:

#include <cstring>
#include <iostream>

class Foo
{
public:
    /** Default constructor */
    Foo() :
        data (new char[14])
    {
        std::strcpy(data, "Hello, World!");
    }

    /** Copy constructor */
    Foo (const Foo& other) :
        data (new char[std::strlen (other.data) + 1])
    {
        std::strcpy(data, other.data);
    }

    /** Move constructor */
    Foo (Foo&& other) noexcept : /* noexcept needed to enable optimizations in containers */
        data(other.data)
    {
        other.data = nullptr;
    }

    /** Destructor */
    ~Foo() noexcept /* explicitly specified destructors should be annotated noexcept as best-practice */
    {
        delete[] data;
    }

    /** Copy assignment operator */
    Foo& operator= (const Foo& other)
    {
        Foo tmp(other); // re-use copy-constructor
        *this = std::move(tmp); // re-use move-assignment
        return *this;
    }

    /** Move assignment operator */
    Foo& operator= (Foo&& other) noexcept
    {
        // simplified move-constructor that also protects against move-to-self.
        std::swap(data, other.data); // repeat for all elements
        return *this;
    }

private:
    friend std::ostream& operator<< (std::ostream& os, const Foo& foo)
    {
        os << foo.data;
        return os;
    }

    char* data;
};

int main()
{
    const Foo foo;
    std::cout << foo << std::endl;

    return 0;
}

我想这是暗示为什么设置(未初始化/未分配)悬挂指针到nullptr的重要性,因为这会在删除时阻止析构函数中的内存错误?

我认为这是因为资源通过移动构造函数传输的情况,但是到期对象收到一个永远不会分配的悬空指针 - 我们不希望随后调用析构函数并{{1指针 - 除非我们确保它指向delete(无操作)。

任何人都可以澄清我提出的一些观点吗?

0 个答案:

没有答案