2017-03-08 180 views
2

我正在尝试C++自己,我真的变得有点困惑。
我真的有理解构造/复制构造/移动构造/析构的问题,并正确设置它们。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) 

回答

1

你的移动构造函数不是移动什么,我t只是复制长度和指针(意思就像默认的复制构造函数一样)。这意味着您将有两个Container对象,其中的data成员将指向相同的内存。

当内存被删除的对象之一,导致未定义的行为当第二个对象试图删除相同的内存。

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

1

正如一些程序员花花公子解释说,这一举动构造会做:

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

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

复制asignement函数可以是这样:

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; 
} 
1

你的拷贝构造是细(但可以使用手动回路的复制算法代替被简化)。

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

而你的operator+operator-应该通过引用而不是按值来引用它们的输入,并且它们自己被声明为const。他们也没有考虑到输入Container可能与Container有不同的length被执行。

尝试更多的东西是这样的:

#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); 
    } 
}