C ++ - 构造函数,复制构造函数,移动构造函数,析构函数

时间:2017-03-08 12:28:36

标签: c++ constructor copy destructor move

我自己在尝试C ++,而且我真的感到有些困惑 我真的遇到了解构造函数/复制构造函数/移动构造函数/析构函数并正确设置它们的问题。

我想在class Container中实现副本以及移动构造函数和析构函数。我首先尝试了复制构造函数,并认为我做对了。不幸的是,析构函数允许程序在尝试执行delete[] data时因某种原因而崩溃。 我认为我之前出现了错误,因为data字段已不存在了,我将其复制错误或其他任何内容。我希望你能帮助我,理解我的错误。 我还尝试了一个移动构造函数(下面),这绝对不起作用。

感谢帮助人员。希望以后能够回馈:)

容器类:

#include <iostream>
#include <memory>

class Container
{
public:
Container()
{
    length = 0;
    data = nullptr;
}

Container(int lengthin):Container()
{
    length = lengthin;
    data = new double[lengthin];
    //data[lengthin];
    //double data[lengthin] = {0};
}

Container(std::initializer_list<double> listin)
        :Container((int)listin.size())
{
    std::uninitialized_copy ( listin.begin(), listin.end(), data);
}

//copy constructor - working? 
Container(const Container& other):Container(other.length)
{
    //data = other.data;
    //length = other.length;
    for (auto i=0; i<other.length; i++)
    {
        data[i] = other.data[i];
    }
}


//~Container(){length = 0;}
~Container()
{
    delete[] data;
    length = 0;
}


Container operator+(Container cin)
{
    Container cout(cin.length);
    cout.length = cin.length;
    for (auto i=0; i<cin.length; i++)
    {
        cout.data[i] = cin.data[i] + data[i];
    }
    return cout;
}

Container operator-(Container cin)
{
    Container cout(cin.length);
    cout.length = cin.length;
    for (auto i=0; i<cin.length; i++)
    {
        cout.data[i] = data[i]-cin.data[i];
    }
    return cout;
}


void print(const std::string &info) const
{
    // print the address of this instance, the attributes `length` and
    // `data` and the `info` string
    std::cout << "  " << this << " " << length << " " << data << "  "
              << info << std::endl;
}

private:
    int length;
    double *data;
};

主程序:

int main()
{
Container a({ 1, 2, 3 });
std::cout << "  a has address " << &a << std::endl;

Container b = { 4, 5, 6 };  
std::cout << "  b has address " << &b << std::endl;

Container c(a);
std::cout << "  c has address " << &c << std::endl;

Container d = a + b;
std::cout << "  d has address " << &d << std::endl;

Container e;
std::cout << "  e has address " << &e << std::endl;

e = a + b;

//Container f(std::move(a + b));   
//std::cout << "  f has address " << &f << std::endl;

return 0;}

尝试过的移动构造函数:

Container(const Container&& other):length(other.length), data(other.data)

3 个答案:

答案 0 :(得分:1)

你的移动构造函数不会移动任何东西,它只是复制长度和指针(意味着它就像默认的复制构造函数一样)。这意味着您将拥有两个Container个对象,其data成员将指向相同的内存。

当删除内存中的一个对象时,当第二个对象尝试删除相同的内存时,会导致未定义的行为

解决此问题的一种简单方法是将其他对象length设置为零,将data指针设置为nullptr。或者默认初始化当前对象,然后交换这两个对象。

答案 1 :(得分:1)

正如一些程序员老兄所解释的那样,这个移动构造函数会这样做:

Container(Container&& other):length(other.length), data(other.data)
{
other.length = 0;
other.data = nullptr;
}

other.data = nullptr;因此,当调用其他的析构函数时,delete []data将不起作用(当前代码会使您刚刚移动到的Container所拥有的数据数组无效。 other.length = 0;因为其他没有数据数组,所以它也应该没有长度。 请注意,我只发布了代码,因为显然你自己发布了一个错误的答案(似乎第一个答案不清楚代码应该是什么)。 另外,因为这是一个构造函数,所以你不必担心this->data注意,使用移动对象运算符,你必须先delete this->data[]以避免内存泄漏。

副本设置功能可以是这样的:

Container& operator=(const Container &other)
{
    if (this->length)
    delete[] this->data;
    this -> length = other.length;
    data = new double [this->length];
    for (auto i = 0; i<other.length; i++)
    {
        this->data[i] = other.data[i];
    }
    return *this;
}

答案 2 :(得分:1)

您的复制构造函数很好(但可以使用复制算法而不是手动循环进行简化)。

您的类缺少复制赋值运算符,移动构造函数和移动赋值运算符。

您的operator+operator-应该通过引用而非值来获取输入,并将它们自己声明为const。他们也没有考虑输入Container可能与length的行为不同Container

尝试更像这样的事情:

#include <iostream>
#include <algorithm>

class Container
{
public:
    Container() : length(0), data(nullptr)
    {
    }

    Container(int len) : Container()
    {
        length = len;
        data = new double[len];
    }

    Container(std::initializer_list<double> src) : Container((int)src.size())
    {
        std::uninitialized_copy(src.begin(), src.end(), data);
    }

    Container(const Container &src) : Container(src.length)
    {
        std::uninitialized_copy(src.data, src.data + src.length, data);
    }

    Container(Container &&src) : Container()
    {
        src.swap(*this);
    }

    ~Container()
    {
        delete[] data;
        length = 0;
    }

    void swap(Container &other) noexcept
    {
        std::swap(data, other.data);
        std::swap(length, other.length);
    }

    Container& operator=(const Container &rhs)
    {
        if (length < rhs.length)
        {
            Container tmp(rhs);
            swap(tmp);
        }
        else
        {
            length = rhs.length;
            std::uninitialized_copy(rhs.data, rhs.data + rhs.length, data);
        }
        return *this;        
    }

    Container& operator=(Container&& rhs)
    {
        rhs.swap(*this);
        return *this;        
    }

    Container operator+(const Container &rhs) const
    {
        int len = std::max(length, rhs.length);
        Container out(len);
        for (auto i = 0; i < len; ++i)
        {
            if ((i < length) && (i < rhs.length))
                out.data[i] = data[i] + rhs.data[i];
            else
                out[i] = (i < length) ? data[i] : rhs.data[i];
        }
        return out;
    }

    Container operator-(const Container &rhs) const
    {
        int len = std::max(length, rhs.length);
        Container out(len);
        for (auto i = 0; i < len; ++i)
        {
            if ((i < length) && (i < rhs.length))
                out.data[i] = data[i] - rhs.data[i];
            else
                out[i] = (i < length) ? data[i] : rhs.data[i];
        }
        return out;
    }

    void print(const std::string &info) const
    {
        // print the address of this instance, the attributes `length` and
        // `data` and the `info` string
        std::cout << " " << this << " " << length << " " << data << " " << info << std::endl;
    }

private:
    int length;
    double *data;
};

namespace std
{
    void swap(Container &lhs, Container &rhs)
    {
        lhs.swap(rhs);
    }
}

然后,您可以使用std::vector而不是手动数组来大大简化事情:

#include <iostream>
#include <algorithm>
#include <vector>

class Container
{
public:
    Container(size_t len = 0) : data(len)
    {
    }

    Container(std::initializer_list<double> src) : data(src)
    {
    }

    void swap(Container &other) noexcept
    {
        std::swap(data, other);
    }

    Container operator+(const Container &rhs) const
    {
        size_t thislen = data.size();
        size_t thatlen = rhs.data.size();
        size_t len = std::max(thislen, thatlen);
        Container out(len);
        for (auto i = 0; i < len; ++i)
        {
            if ((i < thislen) && (i < thatlen))
                out.data[i] = data[i] + rhs.data[i];
            else
                out[i] = (i < thislen) ? data[i] : rhs.data[i];
        }
        return out;
    }

    Container operator-(const Container &rhs) const
    {
        size_t thislen = data.size();
        size_t thatlen = rhs.data.size();
        size_t len = std::max(thislen, thatlen);
        Container out(len);
        for (auto i = 0; i < len; ++i)
        {
            if ((i < thislen) && (i < thatlen))
                out.data[i] = data[i] - rhs.data[i];
            else
                out[i] = (i < thislen) ? data[i] : rhs.data[i];
        }
        return out;
    }

    void print(const std::string &info) const
    {
        // print the address of this instance, the attributes `length` and
        // `data` and the `info` string
        std::cout << " " << this << " " << data.size() << " " << data.data() << " " << info << std::endl;
    }

private:
    std::vector<double> data;
};

namespace std
{
    void swap(Container &lhs, Container &rhs)
    {
        lhs.swap(rhs);
    }
}